#!/usr/bin/perl

use strict;
use warnings;
package watch;
use Mojolicious::Lite -signatures;
use File::Slurp;
use Mojo::JSON qw(decode_json encode_json);
use SQL::Abstract;
use Mojo::SQLite;
use Time::Local;
use Data::Dumper;
use URI::Encode qw(uri_encode uri_decode);
use Mojo::Util qw(secure_compare);
plugin 'RenderFile';
require './subroutines.pl';
require './teletype.pl';
require './Websocket.pl';
require './Manager.pl';
print('Watch pwd: ' . `pwd` . "\n\n");
my $config_file = read_file('./config.json');
my $config = decode_json $config_file;
my $device = &subs::device_setter();
our $logfile = &subs::home($config->{'logfile'});
`touch $logfile` if not -e $logfile;
our $log = Mojo::Log->new(path => $logfile);


sub embeddedAuthorizer($c) {
	my $edt = $c->param('edt');
	my $chip_id = $c->param('chip_id');
	my $wat_set = &subs::setting_grabber({ app => $edt, setting => 'operator_door', device => $device, subsetting => $chip_id });;
	my $watch_settings = eval { return decode_json $wat_set } || {};
	my $auth = $watch_settings->{'__specs'}->{'authorization'};
	my $author = `echo $auth | base64 --decode`;
	my $authorization = &subs::note_decrypter($watch_settings->{'__shutup'}->{'patience'}, $author);
	my $rauth = $c->param('authorization');
	my $rauthorization = `echo $rauth | base64 --decode`;
	my $remote_auth = &subs::note_decrypter($watch_settings->{'__shutup'}->{'patience'}, $rauthorization);

	if ($remote_auth && $edt && secure_compare $remote_auth, $authorization) {
		$watch_settings->{'__shutup'} = undef;
		return $watch_settings;
	}
	else {
		return undef;
	}
}

get '/watch/time' => sub($c) {
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $edt = $c->param('edt');
		my $server_time = time();
		my @t = localtime(time);
		my $is_dst = $t[8];
		my $offset = timegm(@t) - timelocal(@t);
		if ($is_dst == 0 && $edt eq 'watch') { 
			$server_time = $server_time + (1000 * 3600);
		}
		my $returner = encode_json { timestamp => $server_time, offset => $offset };
		$c->render(text => $returner);
	}
	else {
		$c->render(template => 'guest_layouts/denial');
	}
};


get '/watch/asset' => sub($c) {
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $filename = $c->param('filename');
		my $paths = Mojo::File->new('public/' . $filename);
		$c->render_file('filepath' => $paths->to_string);
	}
	else {
		$c->render(template => 'guest_layouts/denial');
	}
};

get '/teletype/wifi_update' => sub($c) {
	my $edt = $c->param('edt');
	my $timestamp = $c->param('timestamp');
	my $json_wifi = &subs::setting_grabber({ app => $edt, setting => 'wifi'}) || '{}';
	
	my $wifi = decode_json $json_wifi;
	$c->render(text => $json_wifi);
};

get '/embedded/teletype/backup' => sub($c) {
	if (my $watch_settings = &embeddedAuthorizer($c)) {

		my $b = $c->param('archive');

		my $paths = Mojo::File->new($b);
		$c->render_file('filepath' => $paths->to_string);
	}
	else {
		$c->render(template => 'guest_layouts/denial');
	}
};


get '/watch' => sub($c) {
	my $edt = $c->param('edt');
	my $timestamp = $c->param('timestamp');
	my $room = $c->param('room');
	my $chip_id = $c->param('chip_id');
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $room_count = $watch_settings->{'__specs'}->{'room_count'};
		my $room_max = $watch_settings->{'__specs'}->{'room_max'};
		foreach my $k ( keys %{$watch_settings} ) {
			$watch_settings->{$k}->{'toggle'} = &subs::setting_grabber({ app => $watch_settings->{$k}->{'app'}, setting => 'toggle' }) eq 'on' ? 1 : 0;
		}
		$watch_settings = &subs::embedded_internal_jobs($watch_settings);

		$c->render('json' => $watch_settings);
		&Websocket::send('tab', { console => 'nowMeSuccess(\'' . $edt . '\',\'' . $chip_id . '\')', browser_tab_id => $c->param('browser_tab_id') });
	}
	else { 
		$c->render('text' => "No!"); 
	}
};

get '/watch/telephone_msg' => sub($c) {
	my $timestamp = &subs::rightNow() || $c->param('timestamp');
	my $server_time = &subs::rightNow();
	my $message = $c->param('msg');
	my $app = $c->param('app');
	my $app = &subs::unformat_name($c->param('app'));
	my ($db,$database) = &subs::database_grabber();
	my $insert = &subs::db_insert('appointments', {
		app => $app,
		server_time => $server_time,
		timestamp => $timestamp,
		type => 'msg',
		data => &subs::format_name($message),
		uuid => &subs::random_string_creator(40),
	});
	my $msg = { app => $app, uuid => &subs::random_string_creator(6), console => 'appointmentGrabber("' . $app . '",' . $timestamp . ')' };
	&Websocket::send('server', $msg );

	$c->render('json' => { 'msg' => $message });
};

get '/watch/button' => sub($c) {
	my $edt = $c->param('edt');
	my $chip_id = $c->param('chip_id');
	my $remote_address = $c->tx->remote_address;
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $button = $c->param('button');

		my $timestamp = $c->param('timestamp') * 1000 || &subs::rightNow();
		my $room = $c->param('room');
		my $toggle = $c->param('toggle');
		if ($toggle == 1) {
			$toggle = 'off'
		}
		else {
			$toggle = 'on';
		}



		&subs::setting_setter({ app => $b->{'app'}, setting => 'toggle', value => $toggle });

		my $returner = &subs::edt_button_presser({
			timestamp => $timestamp,
			room => $room,
			watch_settings => $watch_settings,
			button => $button,
			edt => $edt,
			chip_id => $chip_id,
			remote_address => $remote_address,
			toggle => $toggle
		});
		$c->render('json' => $returner);
	}
	else { $c->render("text" => "No!" ); }
};

get '/watch/switch' => sub($c) {
	my $edt = $c->param('edt');
	my $chip_id = $c->param('chip_id');
	my $remote_address = $c->tx->remote_address;
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $button = $c->param('switch');
		my $state = $c->param('state');
		my $toggle = $c->param('toggle');
		my $timestamp = $c->param('timestamp') * 1000 || &subs::rightNow();
		my $room = $c->param('room');
		if ($state eq 'on') {
			$state = 'off'
		}
		else {
			$state = 'on';
		}
		my $syl_count = 10;
		$syl_count = 1 unless $edt eq 'microcontroller';
		my $b = $watch_settings->{&subs::shorthand_name('switch', $syl_count) . $button} || {};
		&subs::setting_setter({ app => $b->{'app'}, setting => 'toggle', value => $state });
		my $data = {
			timestamp => $timestamp,
			room => $room,
			watch_settings => $watch_settings,
			button => $button,
			component => 'switch',
			edt => $edt,
			chip_id => $chip_id,
			remote_address => $remote_address
		};
		$data->{'switch'} = $button;
		if ($data->{'toggle'} == 1) {
			$data->{'state'} = 'on';
		}
		else {
			$data->{'state'} = 'off';
		}
		my $returner = &subs::edt_button_presser($data);
		$c->render(json => $returner);
	}
	else {
		$c->render('text' => 'No!');
	}
};

get '/watch/measure' => sub($c) {
	my $remote_address = $c->tx->remote_address;
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		$c->render('text' => 'ok');		

		my $component = $c->param('component');
		my $chip_id = $c->param('chip_id');
		my $measure = $c->param('measure');
		my $button = $c->param('button');
		my $edt = $c->param('edt');
		my $room = $c->param('room');
		my $timestamp = &subs::rightNow();


		my $emin = $c->param('min');
		my $emax = $c->param('max');
		my $syl_count = 10;
		$syl_count = 1 unless $edt eq 'microcontroller';
		my $b = $watch_settings->{&subs::shorthand_name($component, $syl_count) . $button} || {};

		my $app = $b->{'app'};
		my $settings = &subs::settings_grabber({ app => $app, settings => ['app_measures'] });
		my $app_measures = eval { return decode_json $settings->{'app_measures'} } || [];
		if (exists $app_measures->{$b->{'measure'}}->{'max'} && exists $app_measures->{$b->{'measure'}}->{'min'}) {
			my $etotal = $emax - $emin;

			my $estate = $measure - $emin;
			my $eratio = $estate / $etotal;
			my $total = $app_measures->{$b->{'measure'}}->{'max'} - $app_measures->{$b->{'measure'}}->{'min'};
			my $state_total = $eratio * $total;

			$measure = sprintf("%.3f", $state_total + $app_measures->{$b->{'measure'}}->{'min'});
			my $state = $state_total / $total * 100;
		}

		my $returner = &subs::edt_button_presser({
			timestamp => $timestamp,
			room => $room,
			watch_settings => $watch_settings,
			button => $button,
			edt => $edt,
			chip_id => $chip_id,
			measure => $measure,
			component => $component,
			remote_address => $remote_address
		});
	}

	else { $c->render("text" => "No!" ); }
};

any '/watch/chat_received' => sub ($c) {
	my $message = $c->param('message');

	my $username = $c->param('username');
	my $timestamp = $c->param('timestamp');
	my $contact = $c->param('contact');
	my $community = $c->param('community');
	my $club = $c->param('club');
	my $team = $c->param('team');
	my $project = $c->param('project');
	my $account = $c->param('account');
	my $person = $c->param('person');
	my $authorization = $c->param('authorization');
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my ($db,$database,$sql) = &subs::database_grabber();
		my $ticket = &subs::db_query('select uuid from tickets where name = ?', $contact);
		my $contact_uuid = $ticket->hashes->[0]->{'uuid'};
		&subs::db_insert('mailbox', {
			uuid => &subs::random_string_creator(25),
			timestamp => &subs::rightNow(),
			server_time => &subs::rightNow(),
			body => $message,
			manager_file => $username,
			status => 'public',
			project => $project || $gb::social_constructs->{'projects'}->{'def'},
			account => $account || $gb::social_constructs->{'accounts'}->{'def'},
			community => $community || $gb::social_constructs->{'communities'}->{'def'},
			club => $club || $gb::social_constructs->{'clubs'}->{'def'},
			team => $team || $gb::social_constructs->{'teams'}->{'def'},
			person => $person || $gb::social_constructs->{'people'}->{'def'},
			contact => $contact_uuid || $watch_settings->{'__specs'}->{'computer'}
		});
		$c->render(json => { returner => $username . ": " . $message });
	}
	else {
		$c->render(json => { returner => "P: NO!!!!" });
	}
};


get '/teletype/pen' => sub($c) {
	my $returner = {};
	if (my $watch_settings = &embeddedAuthorizer($c)) {

		&subs::db_insert('mailbox', {
			uuid => &subs::random_string_creator(25),
			timestamp => &subs::rightNow(),
			server_time => &subs::rightNow(),
			body => $c->param('message'),
			manager_file => $c->param('username'),
			status => 'public',
			contact => 'pen'
		});
		my $return_msg = &subs::pen_message({ 'msg' => $c->param('message') });
		$returner = { message => $return_msg };
	}
	else {
		$returner->{'message'} = "i don't know you";
	}
	$c->render(json => $returner);
};

get '/watch/chat_grabber' => sub($c) {
	my $secret = $c->param('s');
	my $timestamp = $c->param('ts');
	my $uuid = $c->param('uuid');
	my $chip_id = $c->param('chip_id');
	my $wat_set = &subs::setting_grabber({ app => 'watch', setting => 'operator_door', subsetting => $chip_id });;
	my $op_d = eval { return decode_json $wat_set } || {};
	my $s = `(echo $secret) | base64 --decode`;
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $pass = &subs::note_decrypter($op_d->{'__shutup'}->{'patience'},$s);
		my ($db,$database,$sql) = &subs::database_grabber();
		my $q = &subs::db_query('select * from mailbox where uuid = ?', $uuid);
		my $mail = $q->hashes->[0];
		my $mb = &subs::note_decrypter($pass, $mail->{'body'}, $mail->{'timestamp'});
		chomp $mb;
		$mail->{'body'} = $mb;
		$c->render(json => $mail);
	}
	else {
		$c->render('text' => 'fuck you');
	}
};

get '/watch/alive' => sub($c) {
	$c->render(text => "alive");
};

get '/watch/ota_status' => sub($c) {
	if (my $watch_settings = &embeddedAuthorizer($c)) {
		my $file = './jp/alarmclock/build/rp2040.rp2040.rpipico2w/alarmclock.ino.bin';
		my $total_size = -s $file;

		my $percentage = sprintf("%.2f", $c->param('current_size') / $total_size * 100 ) . '%';
		$c->render(text => $total_size);
		&Websocket::send('tab', { console => '$(\'#embedded_ota_uploader_percentage\').text(\'' . &subs::format_name($c->param('status')) . ' ' . $percentage . '\').show()', browser_tab_id => $c->param('browser_tab_id') });
	}
	else {
		$c->render(text => 'no');
	}
};

if ($ENV{PURPOSE} eq "watch") { 
	app->secrets($gb::secret_maker);
	app->sessions->cookie_name($ENV{'cookie_name'});
	app->start;
}
else {
	1;
}
