#!/usr/bin/env raku

use Datastar::SDK;
use Datastar::Example::HTTP;

constant DEFAULT-PORT = 9001;
constant DEFAULT-PAGE = $?FILE.IO.parent.add('hotreload.html').Str;

sub file-version(IO::Path:D $page --> Str) {
    return 'missing' unless $page.f;
    $page.modified.Str ~ ':' ~ $page.s;
}

sub watch-page(%request, $connection, IO::Path:D $page --> Nil) {
    my $request = SocketRequest.new(
        :method(%request<method>),
        target => %request<target>,
        body => %request<body>,
        protocol => %request<protocol>,
    );
    my $response = SocketResponse.new(connection => $connection);
    my $sse = ServerSentEventGenerator.new(
        request => $request,
        response => $response,
    );
    my $initial-version = file-version($page);

    loop {
        sleep 0.1;
        if file-version($page) ne $initial-version {
            $sse.execute-script('window.location.reload()');
            return;
        }
    }
}

sub handle-request(
    %request,
    $connection,
    IO::Path:D $page,
    --> Nil
) {
    if %request<method> ne 'GET' {
        $connection.print(http-response(405, 'method not allowed'));
    }
    elsif %request<path> eq '/' {
        if $page.f {
            $connection.print(http-response(
                200,
                $page.slurp,
                content-type => 'text/html; charset=utf-8',
            ));
        }
        else {
            $connection.print(http-response(
                404,
                "missing example page: {$page.Str}",
            ));
        }
    }
    elsif %request<path> eq '/hotreload' {
        watch-page(%request, $connection, $page);
    }
    else {
        $connection.print(http-response(404, 'not found'));
    }
}

sub MAIN(
    Int $port = DEFAULT-PORT,
    Str $page = DEFAULT-PAGE,
) {
    my $page-path = $page.IO;

    serve(
        -> %request, $connection {
            handle-request(%request, $connection, $page-path);
        },
        :$port,
    );
}
