<?php
class Cron {
    private $now = 0;
    private $sender = '';
    private $error = '';
    private $kvs;
    private $ldap;
    public function __construct($sender, $error, $prefix) {
        $this->now = new DateTimeImmutable();
        $this->sender = $sender;
        $this->error = $error;
        $this->subject_prefix = $prefix;
        $this->warn_time = DateInterval::createFromDateString('3 days');
        $this->warn_date = $this->now->add($this->warn_time);
        $this->run_interval = DateInterval::createFromDateString('1 day');
        $this->kvs = new Kvs();
        $this->ldap = new Ldap();

        $days = $this->warn_time->d;
        $this->strings = array(
            'en' => array(
                'new' => array(
                    'single' => "The following loan has been registered in your name:",
                    'multi'  => "The following loans have been registered in your name:",
                    'expiry' => "expires on",
                    'serial' => "serial number",
                ),
                'extend' => array(
                    'single' => "The following loan has been extended:",
                    'multi'  => "The following loans have been extended:",
                    'expiry' => "extended to",
                    'serial' => "serial number",
                ),
                'expiring' => array(
                    'single' => "The following loan expires in less than $days days:",
                    'multi'  => "The following loans expire in less than $days days:",
                    'expiry' => "expires on",
                    'serial' => "serial number",
                ),
                'overdue' => array(
                    'single' => "The following loan has expired:",
                    'multi'  => "The following loans have expired:",
                    'expiry' => "expired on",
                    'serial' => "serial number",
                ),
            ),
            'sv' => array(
                'new' => array(
                    'single' => "Följande lån har registrerats på din användare:",
                    'multi'  => "Följande lån har registrerats på din användare:",
                    'expiry' => "går ut",
                    'serial' => "artikelnummer",
                ),
                'extend' => array(
                    'single' => "Följande lån har förlängts:",
                    'multi'  => "Följande lån har förlängts:",
                    'expiry' => "förlängt till",
                    'serial' => "artikelnummer",
                ),
                'expiring' => array(
                    'single' => "Följande lån går ut om mindre än $days dagar:",
                    'multi'  => "Följande lån går ut om mindre än $days dagar:",
                    'expiry' => "går ut",
                    'serial' => "artikelnummer",
                ),
                'overdue' => array(
                    'single' => "Följande lån har gått ut:",
                    'multi'  => "Följande lån har gått ut:",
                    'expiry' => "gick ut",
                    'serial' => "artikelnummer",
                ),
            ),
        );
    }

    public function run() {
        $this->run_receipts();
        $this->run_reminders();
    }

    private function run_receipts() {
        begin_trans();
        $get = prepare('select * from `pending_receipt`
                        where `send_time` < ?');
        bind($get, 'i', $this->now->getTimestamp());
        execute($get);
        foreach(result_list($get) as $row) {
            $user = new User($row['user']);
            $since_time = $row['since_time'];

            $new_loans = array();
            $extended_loans = array();
            foreach($user->get_loans('active') as $loan) {
                if($loan->get_starttime() >= $since_time) {
                    $new_loans[] = $loan;
                } else if($loan->get_last_extension() >= $since_time) {
                    $extended_loans[] = $loan;
                }
            }
            if($new_loans || $extended_loans) {
                $this->send_receipt($user, $new_loans, $extended_loans);
            }
            $delete = prepare('delete from `pending_receipt`
                               where `user` = ? and `send_time` < ?');
            bind($delete, 'ii', $user->get_id(), $this->now->getTimestamp());
            execute($delete);
        }
        commit_trans();
    }

    private function make_receipt_subject($num_new, $num_extended) {
        $subject = $this->subject_prefix;
        $messages = array();
        if($num_new > 1) {
            $messages[] = $num_new." nya";
        } else if($num_new > 0) {
            $messages[] = $num_new." nytt";
        }
        if($num_extended > 1) {
            $messages[] = $num_extended." förlängda";
        } else if($num_extended > 0) {
            $messages[] = $num_extended." förlängt";
        }
        return $subject.implode(" och ", $messages)." lån";
    }

    private function send_receipt($user, $new, $extended) {
        $uid = $user->get_name();
        $name = $this->ldap->get_firstname($uid);

        $new_count = count($new);
        $extended_count = count($extended);
        $subject = $this->make_receipt_subject($new_count, $extended_count);

        $list_sv = array();
        $list_en = array();
        if($new_count > 0) {
            $list_sv[] = $this->make_notice('sv', 'new', $new);
            $list_en[] = $this->make_notice('en', 'new', $new);
        }
        if($extended_count > 0) {
            $list_sv[] = $this->make_notice('sv', 'extend', $extended);
            $list_en[] = $this->make_notice('en', 'extend', $extended);
        }
        $list_sv = implode("\n\n", $list_sv);
        $list_en = implode("\n\n", $list_en);

        $info_sv = array();
        $info_en = array();
        if($new_count > 0) {
            $info_sv[] = "Eventuella artiklar du inte hämtat ut redan kan hämtas från Helpdesk.";
            $info_en[] = "Any products you haven't already picked up can be collected from Helpdesk.";
        }
        $info_sv[] = "Svara på det här mailet om du har några frågor.";
        $info_en[] = "Please reply to this email if you have any questions.";
        $info_sv = implode(' ', $info_sv);
        $info_en = implode(' ', $info_en);

        $message = <<<EOF
Hej $name!

Det här är ett automatiskt meddelande från Helpdesk.

$list_sv

$info_sv

----

This is an automated message from Helpdesk.

$list_en

$info_en

Mvh
DSV Helpdesk
helpdesk@dsv.su.se
08 - 16 16 48

EOF;
        $this->send_email($uid, $subject, $message);
    }

    private function run_reminders() {
        $lastrun = $this->kvs->get_value('lastrun', 0);
        $nextrun = $this->now
                        ->setTimestamp($lastrun)
                        ->add($this->run_interval);
        if($nextrun > $this->now) {
            return;
        }
        $this->kvs->set_key('lastrun', $this->now->getTimestamp());

        $users = get_items('user');
        foreach($users as $user) {
            $this->check_loans($user);
        }
    }

    private function check_loans($user) {
        $expiring = $user->get_expiring_loans($this->warn_date);
        $overdue = $user->get_overdue_loans();
        if($expiring || $overdue) {
            $this->send_reminder($user, $expiring, $overdue);
        }
    }

    private function make_reminder_subject($num_expiring, $num_expired) {
        $subject = $this->subject_prefix;
        $messages = array();
        if($num_expiring > 0) {
            $messages[] = $num_expiring." utgående";
        }
        if($num_expired > 1) {
            $messages[] = $num_expired." försenade";
        } elseif($num_expired > 0) {
            $messages[] = $num_expired." försenat";
        }
        return $subject.implode(" och ", $messages)." lån";
    }

    private function make_notice($lang, $type, $list) {
        if(!$list) {
            return '';
        }
        if(!array_key_exists($lang, $this->strings)) {
            throw new Exception("Invalid languange: $lang");
        }
        $strings = $this->strings[$lang];
        if(!array_key_exists($type, $strings)) {
            throw new Exception("Invalid type: $type");
        }
        $strings = $strings[$type];

        $lines = array();
        foreach($list as $loan) {
            $product = $loan->get_product();
            $serial = $product->get_serial();
            $brand = $product->get_brand();
            $name = $product->get_name();
            $endtime = format_date($loan->get_endtime());

            $lines[] = "$brand $name, ".$strings['serial']
                      ." $serial, ".$strings['expiry']." $endtime";
        }

        $msg = $strings['single'];
        if(count($list) > 1) {
            $msg = $strings['multi'];
        }
        return $msg."\n\n".implode("\n", $lines);
    }

    private function make_return_info($lang, $count) {
        switch($lang) {
            case 'sv':
                if($count > 1) {
                    $loan = "lånen";
                    $product = "artiklarna";
                } else {
                    $loan = "lånet";
                    $product = "artikeln";
                }
                return "Vänligen kontakta Helpdesk för att förlänga $loan eller lämna tillbaka $product.";
                break;
            case 'en':
                if($count > 1) {
                    $loan = "loans";
                    $product = "items";
                } else {
                    $loan = "loan";
                    $product = "item";
                }
                return "Please contact Helpdesk in order to extend the $loan or return the $product.";
                break;
            default:
                throw new Exception("Invalid language: ".$lang);
        }

    }

    private function send_reminder($user, $expiring, $overdue) {
        $uid = $user->get_name();
        $name = $this->ldap->get_firstname($uid);

        $expiring_count = count($expiring);
        $overdue_count = count($overdue);
        $total = $expiring_count + $overdue_count;

        $subject = $this->make_reminder_subject($expiring_count,
                                                $overdue_count);

        $info_sv = array();
        $info_en = array();
        if($expiring_count > 0) {
            $info_sv[] = $this->make_notice('sv', 'expiring', $expiring);
            $info_en[] = $this->make_notice('en', 'expiring', $expiring);
        }
        if($overdue_count > 0) {
            $info_sv[] = $this->make_notice('sv', 'overdue', $overdue);
            $info_en[] = $this->make_notice('en', 'overdue', $overdue);
        }
        $info_sv = implode("\n\n", $info_sv);
        $returns_sv = $this->make_return_info('sv', $total);

        $info_en = implode("\n\n", $info_en);
        $returns_en = $this->make_return_info('en', $total);

        $message = <<<EOF
Hej $name!

Det här är en automatisk påminnelse om lånade artiklar från Helpdesk.

$info_sv

$returns_sv

----

This is an automated reminder regarding items on loan from Helpdesk.

$info_en

$returns_en

Mvh
DSV Helpdesk
helpdesk@dsv.su.se
08 - 16 16 48

EOF;
        $this->send_email($uid, $subject, $message);
    }

    private function send_email($uid, $subject, $message) {
        try {
            mb_send_mail($this->ldap->get_user_email($uid),
                         $subject,
                         $message,
                         'From: '.$this->sender);
        } catch(Exception $e) {
            error_log($e->getMessage());
            mb_send_mail($this->error,
                         "Kunde inte skicka mail",
                         "Mail kunde inte skickas till ".$uid);
        }
    }
}
?>