#!/usr/bin/env perl
# repl — evaluate Lisp forms against the running Passepartout daemon
# Usage: repl <lisp-form>
#   or: echo '<lisp-form>' | repl
#
# Connects to the daemon on 127.0.0.1:9105, sends a repl-eval request
# via the framed TCP protocol, reads and prints the response.

use strict;
use warnings;
use IO::Socket::INET;

my $HOST  = $ENV{PASSEPARTOUT_HOST} || "127.0.0.1";
my $PORT  = $ENV{PASSEPARTOUT_PORT} || "9105";
my $TIMEOUT = $ENV{PASSEPARTOUT_REPL_TIMEOUT} || 10;

my $expr = join(" ", @ARGV);
if (!$expr) {
    $expr = do { local $/; <STDIN> };
}
chomp($expr);
# Quote the expression for embedding in a Lisp string
$expr =~ s/\\/\\\\/g;   # backslash → doubled
$expr =~ s/"/\\"/g;     # " → \"
if (!$expr) {
    die "Usage: repl <lisp-form>\n   or: echo '(+ 1 2)' | repl\n";
}

my $sock = IO::Socket::INET->new(
    PeerHost  => $HOST,
    PeerPort  => $PORT,
    Proto     => "tcp",
    Timeout   => $TIMEOUT
) or die "Cannot connect to $HOST:$PORT: $!\n";

sub read_frame {
    my ($sock) = @_;
    my $hex;
    $sock->read($hex, 6) or return undef;
    my $len = hex($hex);
    my $content;
    $sock->read($content, $len);
    return $content;
}

sub write_frame {
    my ($sock, $content) = @_;
    my $len = sprintf("%06X", length($content));
    $sock->send($len . $content);
}

# Read handshake (discard)
my $handshake = read_frame($sock);

# Build framed message
my $msg = '(:TYPE :EVENT :PAYLOAD (:SENSOR :repl-eval :CODE "' . $expr . '"))';
write_frame($sock, $msg);

# Read response
my $response = read_frame($sock);
if (defined $response) {
    if ($response eq "") {
        print STDERR "Daemon returned empty response\n";
        exit 1;
    }
    if ($response =~ /:VALUE "([^"]*)"/s) {
        print "$1\n";
    } elsif ($response =~ /:message "([^"]*)"/s) {
        print STDERR "$1\n";
        exit 1;
    } else {
        print "Response: $response\n";
    }
} else {
    print STDERR "No response from daemon (is it running on $HOST:$PORT?)\n";
    exit 1;
}
$sock->close();
