#**************************************************************************
#   Copyright (C) 2009 by Michael Andreen <harvATruinDOTnu>               *
#                                                                         *
#   This program is free software; you can redistribute it and/or modify  *
#   it under the terms of the GNU General Public License as published by  *
#   the Free Software Foundation; either version 2 of the License, or     *
#   (at your option) any later version.                                   *
#                                                                         *
#   This program is distributed in the hope that it will be useful,       *
#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#   GNU General Public License for more details.                          *
#                                                                         *
#   You should have received a copy of the GNU General Public License     *
#   along with this program; if not, write to the                         *
#   Free Software Foundation, Inc.,                                       *
#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
#**************************************************************************/

use strict;
use warnings;
use feature ':5.10';


use MooseX::Declare;
use NDIRC::Dispatcher;

command defcall => {
	help => q(syntax: .defcall [callid] | if a call id is given, then shiptypes and eta will be fetched from the database and added to the message),
	type => q(def),
	acl => q(irc_defcall),
}, class extends NDIRC::Command {
	method execute($c,$msg) {
		my ($callnr,$mess) = $msg =~ /^(\d+)?(.*)$/ or die 'ARGS';
		my $dbh = $c->model;

		my $callinfo = "";
		if ($callnr){
			my $st = $dbh->prepare(q{
SELECT status
	,c.landing_tick - (SELECT value::integer FROM misc WHERE id = 'TICK') AS eta
	,array_to_string(array_agg(i.shiptype),'/') AS shiptype
FROM calls c
	JOIN incomings i USING (call)
	LEFT OUTER JOIN users dc ON dc.uid = c.dc
WHERE c.call = ?
GROUP BY c.call,c.landing_tick,c.status
ORDER BY c.landing_tick;
				});
			my $call = $dbh->selectrow_hashref($st,undef,$callnr);
			unless (defined $call->{status}){
				$c->reply("No call with id: $callnr");
				return;
			}
			$callinfo = "(Anti $call->{shiptype} ETA: $call->{eta})";
			if($call->{status} eq 'Covered'){
				$c->reply("Call <b>$callnr</b> $callinfo is covered.");
				return;
			}
		}
		$c->bot->toTarget(members => "DEFENSE REQUIRED "
			."$mess $callinfo RESPOND TO ".$c->username);
	}
};

command settype => {
	help => q(Usage: .settype incId type | or: .settyp callId X:Y:Z type | or: .settypeall callId type),
	type => q(def),
	acl => q(irc_settype),
	alias => q(settypeall),
}, class extends NDIRC::Command {
	use CGI;
	method execute($c,$msg) {
		my $dbh = $c->model;

		my $query = q{
SELECT inc,call,shiptype, coords(x,y,z),c.landing_tick - tick() AS eta
FROM incomings i
	JOIN current_planet_stats p USING (pid)
	JOIN calls c USING (call)
		};
		my $fleets;
		my $type;
		my $call;

		if ($self->name eq 'settypeall'){
			($call,$type) = $msg =~ /^(\d+) (.*)$/ or die 'ARGS';

			$fleets = $dbh->prepare($query . q{
WHERE call = ?
				});
			$fleets->execute($call);
		}else{
			my ($id,$x,$y,$z,$t) = $msg =~ /^(\d+) (\d+):(\d+):(\d+) (.*)$/;
			if (defined $id){
				$fleets = $dbh->prepare($query . q{
WHERE call = ? AND pid = planetid(?,?,?,tick())
					});
				$fleets->execute($id,$x,$y,$z);
			}else{
				($id,$t) = $msg =~ /^(\d+) (.*)$/ or die 'ARGS';
				$fleets = $dbh->prepare($query . q{
WHERE inc = ?
					});
				$fleets->execute($id);
			}
			$type = $t;
		}

		$type = CGI::escapeHTML($type);
		$dbh->begin_work;
		my $deflog = '';
		my $settype = $dbh->prepare(q{UPDATE incomings SET shiptype = ? WHERE inc = ?});
		while (my $inc = $fleets->fetchrow_hashref){
			$call //= $inc->{call};
			if ($inc->{eta} < 0){
				$c->reply("This call is old. Did you use the call id instead of inc id by"
					." accident? You can use .settypeall callid to set the type on all incs"
					." in a call. Or use webbie if you really want to update this old call.");
				$dbh->rollback;
				return;
			}
			$settype->execute($type,$inc->{inc});
			$deflog .= "Set fleet: [B]$inc->{inc} [/B] to: [B]$type [/B]\n";
			$c->reply("Set fleet $inc->{inc} from $inc->{coords} on call $call to $type (previously $inc->{shiptype})");
		}
		if ($fleets->rows == 0){
			$c->reply("No matching fleets");
			$dbh->rollback;
		}else{
			$c->def_log($call,$deflog);
			$dbh->commit;
		}
	}
};

command calltake => {
	help => q(Usage: .calltake callid | sets the dc. also markes as covered/ignored with .callcov and .callignore),
	type => q(def),
	acl => q(irc_calltake),
	alias => [qw/callcov callignore/],
}, class extends NDIRC::Command {
	method execute($c,$msg) {
		my ($id) = $msg =~ /^(\d+)$/ or die 'ARGS';
		my $dbh = $c->model;

		my $status = 'Open';

		given ($self->{name}){
			when('callignore'){
				$status = 'Ignored';
			}
			when('callcov'){
				$status = 'Covered';
			}
		}

		$dbh->begin_work;
		my $rows = $dbh->do(q{
UPDATE calls SET dc = $1
	,status = $3
WHERE call = $2
			},undef,$c->uid,$id,$status);
		if ($rows == 1){
			$c->reply("Setting status on call $id to $status");
			$c->def_log($id , "Changed status: [B]$status [/B]");
			$dbh->commit;
		}else{
			$c->reply("$id is not a valid call");
			$dbh->rollback;
		}
	}
};

command setcalc => {
	help => q(Usage: .setcalc callId calc | sets the calc for the given call.),
	type => q(def),
	acl => q(irc_setcalc),
}, class extends NDIRC::Command {
	use CGI;
	method execute($c,$msg) {
		my ($id,$calc) = $msg =~ /^(\d+) (.+)$/ or die 'ARGS';
		my $dbh = $c->model;

		$dbh->begin_work;
		my $rows = $dbh->do(q{UPDATE calls SET calc = $2 WHERE call = $1}
			,undef,$id, $calc);
		if ($rows == 1){
			$c->reply("Updated calc call <b>$id</b>");
			$calc = CGI::escapeHTML($calc);
			$c->def_log($id , 'Updated calc to: [URL]'.$calc.'[/URL]');
			$dbh->commit;
		}else{
			$c->reply("$id is not a valid call");
			$dbh->rollback;
		}
	}
};

command getcalc => {
	help => q(Usage: .getcalc callId | receives the calc for the given call),
	type => q(def),
	acl => q(irc_getcalc),
}, class extends NDIRC::Command {
	method execute($c,$msg) {
		my ($id) = $msg =~ /^(\d+)$/ or die 'ARGS';
		my $dbh = $c->model;

		my $calc = $dbh->selectrow_array(q{
SELECT calc FROM calls WHERE call = $1}
			,undef,$id);
		$calc //= "Bad call id, there is no such call.";
		$c->reply("Calc for call <b>$id</b>: $calc");
	}
};

command report_incs => {
	help => q(Used to report incs, same as pasting in pm. Use ~ prefix to send output to channel),
	type => q(def),
}, class extends NDIRC::Command {
	use Try::Tiny;
	method execute($c,$msg) {

		$msg =~ /(\d+):(\d+):(\d+)\*?\s+(\d+):(\d+):(\d+)\s+([^:]*\S+)\s+(?:Ter|Cat|Xan|Zik|Etd)\s+([\d,]+)\s+(?:Attack\s+)?(\d+)/
		|| $msg =~ /(\d+):(\d+):(\d+)\s+(\d+):(\d+):(\d+)\s+\((?:Ter|Cat|Xan|Zik|Etd)\)\s+([^,]*\S+)\s+([\d,]+)\s+(\d+)\s+\(\d+\)/
			or return;
		my $dbh = $c->model;
		my $amount = $8;
		{
			$amount =~ s/,//g;
		}

		my $st = $dbh->prepare(q{
SELECT username, uid, pid, defprio
FROM users_defprio u
WHERE pid = planetid($1,$2,$3,tick())
	AND uid IN (SELECT uid FROM groupmembers WHERE gid = 'M')
			});
		if (my $user = $dbh->selectrow_hashref($st,undef,$1,$2,$3)){

			$st = $dbh->prepare(q{
SELECT nick,alliance,pid,planet_status,relationship
FROM current_planet_stats WHERE x = ? AND y = ? AND z = ?
			});
			if (my @attacker = $dbh->selectrow_array($st,undef,$4,$5,$6)){
				try {
					$dbh->begin_work;
					my $landing_tick = $dbh->selectrow_array(q{SELECT tick() + ?},undef,$9);
					my @call = $dbh->selectrow_array(q{
SELECT call,status,calc
FROM calls WHERE uid = ? AND landing_tick = ?
						},undef,$user->{uid},$landing_tick);
					my $threefleeter = $dbh->selectrow_array(q{
SELECT COALESCE(gid = 'X',false)
FROM groupmembers WHERE uid = ? AND gid = 'X'
						},undef,$user->{uid});
					unless (@call){ #call doesn't exists, create a new one
						@call = $dbh->selectrow_array(q{
INSERT INTO calls (uid,landing_tick,info) VALUES(?,?,'') RETURNING call,status,calc
							},undef,$user->{uid},$landing_tick);
						if ($threefleeter){
							$dbh->do(q{UPDATE calls SET status = 'Ignored' WHERE call = $1},undef,$call[0]);
							$c->def_log($call[0], 'This member has been marked as [B]NoDef[/B], do [B]not cover[/B] unless you have a good reaon.');
							$call[1] = 'Ignored';
						}
					}
					my $pointlimits = $dbh->prepare(q{SELECT value :: float FROM misc WHERE id = ?});
					my ($minpoints) = $dbh->selectrow_array($pointlimits,undef,'DEFMINPRIO');
					my ($maxpoints) = $dbh->selectrow_array($pointlimits,undef,'DEFMAXPRIO');
					my $color = 3;
					if ($user->{defprio} < $minpoints){
						$color = 5;
					}elsif ($user->{defprio} < $maxpoints){
						$color = 8;
					}
					$user->{defprio} = "<c0$color>$user->{defprio}</c>";
					$st = $dbh->prepare(q{SELECT pid FROM incomings WHERE pid = ? AND amount = ? and fleet = ? AND call = ?});
					unless (my @inc = $dbh->selectrow_array($st,undef,$attacker[2],$amount,$7,$call[0])){
						my $incid = $dbh->selectrow_array(q{
INSERT INTO incomings (call,pid,eta,amount,fleet) VALUES(?,?,?,?,?) RETURNING inc
						},undef,$call[0],$attacker[2],$9,$amount,$7);
						@attacker = map ($c->valuecolor(0),@attacker);
						if (! $threefleeter || $call[1] ne 'Ignored'){
							$c->bot->toTarget(def => "<b>New incoming: CallId: $call[0], IncId: $incid $1:$2:$3 ($user->{defprio}) is under Attack by $4:$5:$6, ($attacker[3]), $attacker[1]($attacker[4]) https://nd.ruin.nu/calls/edit/$call[0]</b>");
						}else{
							$c->bot->toTarget(def => "<b>Do not cover</b>, NoDef member is under attack by $4:$5:$6, ($attacker[3]), $attacker[1]($attacker[4])  https://nd.ruin.nu/calls/edit/$call[0]");
						}
						$dbh->do(q{UPDATE planets SET hit_us = hit_us + 1 WHERE pid = ?},undef,$attacker[2]);
						if ($call[1] eq 'Covered'){
							$dbh->do(q{UPDATE calls SET status = 'Open' WHERE call = ?},undef,$call[0]);
							$c->bot->toTarget(def => "<b>Call is likely not covered anymore, please recalc! calc: $call[2]</b>");
						}
					}else{
						@attacker = map ($c->valuecolor(0),@attacker);
						$c->bot->toTarget(def => "Duplicate call: Callid: $call[0], Status: $call[1] $1:$2:$3 ($user->{defprio}) is under Attack by $4:$5:$6, ($attacker[3]), $attacker[1]($attacker[4]), landing tick: $landing_tick");
					}

					my ($fleetcatch) = $dbh->selectrow_array(q{
SELECT count(*) FROM launch_confirmations WHERE uid = ? AND back = ?
					},undef,$user->{uid},$landing_tick);
					if ($fleetcatch > 0){
						$c->bot->toTarget(def => "<c04>THIS IS A POSSIBLE FLEETCATCH!</c>");
					}
					$dbh->commit;
				} catch {
					$dbh->rollback;
					die $_;
				};
			}else{
				$c->bot->toTarget(def => "<c04>Didn't find any planet with coordinates $4:$5:$6 at this tick</c>");
			}
		}else{
			$c->bot->toTarget(def => "<c04>No member registered with coordinates $1:$2:$3</c>");
		}
	}
};

1;

