#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

#use Smart::Comments;
use FindBin;
use lib "$FindBin::Bin/../lib";
use OpenResty::Dispatcher;
use OpenResty::Limits;
use Getopt::Std;
use Time::HiRes;
use Digest::MD5 'md5';

my $cmd = lc(shift) || $ENV{OPENRESTY_COMMAND};

if ($ENV{REQUEST_URI}) {
    if (!$cmd) {
        $cmd = 'fastcgi';
        $ENV{OPENRESTY_COMMAND} = $cmd;
    }
}

$cmd ||= '';

eval {
    OpenResty::Dispatcher->init;
};
warn $@ if $@;

if ($cmd eq 'fastcgi') {
    require OpenResty::FastCGI;
    while (my $cgi = new OpenResty::FastCGI) {
        my $begin_time;
        if (defined $OpenResty::Dispatcher::StatsLog) {
            $begin_time = Time::HiRes::time;
        }

        eval {
            OpenResty::Dispatcher->process_request($cgi);
        };
        if ($@) {
            warn $@;
            print "HTTP/1.1 200 OK\n";
            # XXX don't show $@ to the end user...
            print qq[{"success":0,"error":"$@"}\n];
        }
        if (my $stats_dir = $OpenResty::Dispatcher::StatsLog) {
            my $diff = Time::HiRes::time - $begin_time;
            my $now = localtime;
            my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
            $year += 1900; $mon += 1;
            #my $now = "$year-$mon-$mday $hour:$min:$sec";
            #my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
            #$year += 1900; $mon += 1;
            my $stats_file = sprintf("$stats_dir/%04d-%02d-%02d.log", $year, $mon, $mday);
            open my $log, ">>$stats_file" or die "Can't open stats_log file $stats_file for writing: $!\n";
            my $client = $ENV{REMOTE_ADDR};
            my $meth = $ENV{REQUEST_METHOD};
            my $url = $ENV{REQUEST_URI};
            ### %ENV
            print $log sprintf("[%04d-%02d-%02d %02d:%02d:%02d] %.03f %s \"%s %s\"\n", $year, $mon, $mday, $hour, $min, $sec, $diff, $client, $meth, $url);
            close $log;
        }
    }
    exit;
} elsif ($cmd eq 'cgi') {
    require CGI::Simple;
    my $cgi = CGI::Simple->new;
    OpenResty::Dispatcher->process_request($cgi);
    exit;
} elsif ($cmd eq 'start') {
    my %opts;
    getopts('p:', \%opts);
    my $port = $opts{p} || 8000;

    require OpenResty::Server;
    my $server = OpenResty::Server->new;
    $server->port($port);
    $server->run;
    exit;
}

my $error = $OpenResty::Dispatcher::InitFatal;
if ($error) {
    die $error;
}
my $backend = $OpenResty::Backend;

if ($cmd eq 'adduser') {
    my $user = shift or
        die "No user specified.\n";
    if ($backend->has_user($user)) {
        die "User $user already exists.\n";
    }
    eval "use Term::ReadKey;";
    if ($@) { die $@; }
    #local $| = 1;

    my $password;
    print "Enter the password for the Admin role: ";

    ReadMode(2);
    my $key;
    while (not defined ($key = ReadLine(0))) {
    }
    ReadMode(0);

    $key =~ s/\n//s;
    print "\n";

    my $saved_key = $key;
    #warn "Password: $password\n";
    OpenResty::check_password($saved_key);

    print "Re Enter the password for the Admin role: ";

    ReadMode(2);
    while (not defined ($key = ReadLine(0))) {
    }
    ReadMode(0);

    $key =~ s/\n//s;
    print "\n";

    if ($key ne $saved_key) {
        die "2 passwords don't match.\n";
    }
    $password = $key;

    $OpenResty::Backend->add_user($user, $password);
    my $machine = $OpenResty::Backend->has_user($user);
    if ($machine) {
        warn "User $user created on node $machine.\n";
    }
} elsif ($cmd eq 'deluser') {
    my $user = shift or
        die "No user specified.\n";
    if ($backend->has_user($user)) {
        $OpenResty::Backend->drop_user($user);
    } else {
        die "User $user does not exist.\n";
    }
} elsif ($cmd eq 'upgrade') {
    my $user = shift;
    require OpenResty::Script::Upgrade;
    OpenResty::Script::Upgrade->go($backend, $user);
} elsif ($cmd eq '' or $cmd eq 'shell') {
    require OpenResty::Shell;
    my $shell = OpenResty::Shell->new($backend);
    $shell->run;
} elsif ($cmd eq 'updatekey') {
	my $secret=shift||$backend->random_secret();

	die "Invalid captcha secret, must be exactly 16 bytes long and contains only characters in [0-9a-zA-Z].\n"
		unless $backend->is_valid_captcha_secret($secret);

	# the secret format check is done before the updating occurs
	unless($backend->update_captcha_secret($secret)) {
		die "Failed to update captcha secret.\n"
	} else {
		print "Captcha secret updated.\n";
	}
} else {
    die "Unknown command: $cmd\n";
}

