#!/usr/bin/perl

use strict;
use warnings;

use English;
use Carp;
use POSIX qw(setsid);
use IO::Socket::UNIX;
use Hash::Merge qw(merge);
use Template;
use YAML::XS qw(LoadFile);
use Clone 'clone';
use Getopt::Long;

use NGCP::Template;

my $quiet = 0;

GetOptions("q|quiet" => \$quiet);

my $server_socket = get_server_socket();

daemonize();

handle_connections($server_socket, $quiet);

exit;

sub daemonize {
    my $NGCP_BASE_TT2 = $ENV{'NGCP_BASE_TT2'} //= '/';
    chdir $NGCP_BASE_TT2           or croak "Can't chdir to $NGCP_BASE_TT2: $ERRNO";
    open(STDIN,  '<', '/dev/null') or croak "Can't read /dev/null: $ERRNO";
    open(STDOUT, '>', '/dev/null') or croak "Can't write to /dev/null: $ERRNO";
    defined(my $pid = fork)        or croak "Can't fork: $ERRNO";
    exit if $pid;
    setsid()                       or croak "Can't start a new session: $ERRNO";
    open(STDERR, '>&', \*STDOUT)   or croak "Can't dup stdout: $ERRNO";
    return;
}

sub get_server_socket {
    my $NGCP_SOCKETFILE = $ENV{'NGCP_SOCKETFILE'} //= '/var/run/ngcpcfg.socket';

    my $server = IO::Socket::UNIX->new(
        'Type'      => SOCK_STREAM(),
        'Local'     => $NGCP_SOCKETFILE,
        'Listen'    => SOMAXCONN,
    );
    die "Error: can't setup tt2-daemon!\n$EVAL_ERROR\n$ERRNO\n" unless $server;

    binmode $server => ":encoding(utf8)";

    return $server;
}

sub handle_connections {
    my $port = shift;
    my $quiet = shift;
    my $config = {};
    my %loaded_ymls = ();

    while (my $client = $port->accept()) {
        my $input = <$client>;
        chomp $input;

        my @argv = split(' ', $input) or
            print { $client } "Usage: echo '<template> [<config.yml> [<another.yml>]]' | netcat localhost 42042 \n";
        my $template = shift @argv;

        foreach my $file (@argv) {
            next if exists $loaded_ymls{$file};
            $loaded_ymls{$file} = undef;

            print { $client } "Loading $file in memory:" unless $quiet;
            my $hm = Hash::Merge->new('RIGHT_PRECEDENT');
            $config = $hm->merge($config, LoadFile($file));
            print { $client } " OK \n" unless $quiet;
        }

        my $tt = Template->new({
            ABSOLUTE => 1,
            RELATIVE => 1,
            EVAL_PERL => 1
        });
        my $tt_config = clone($config);
        $tt_config->{ngcp} = NGCP::Template->new($tt_config);

        open my $fh, '<', $template or
            print { $client } "Unable to open file '$template' for reading: $ERRNO\n";
        $tt->process($fh, $tt_config, $client) or
            print { $client } $tt->error;
        close $fh;

        close $client;
    }

    return;
}
