<?php

class PancekService
{
    /**
     * @var BaseController $context
     */
    public $context;
    /**
     * @var PancekFormulir $formulir
     */
    public $formulir;

    const ACTION_ASSIGN = "pancek/daftar-verifikator";

    const ACTION_ASSIGN_KPPBC = "pancek/kppbc";
    const ACTION_VERIFY = "pancek/rekapitulasi/instansi";
    const ACTION_REKAPITULASI = "pancek/rekapitulasi";
    const ACTION_FORM = "pancek/form";

    const CEKLIS_KEPENTINGAN_BK = '1;0;0';
    const CEKLIST_KEPENTINGAN_BC = '0;1;0';

    const FLOW_BK = 'BK';
    const FLOW_BC = 'BC';
    const FLOW_KPK = 'KPK';

    public function __construct(BaseController $context)
    {
        $this->context = $context;
    }

    public function handleFormulirSubmitNotification(PancekFormulir $formulir)
    {
        $this->formulir = $formulir;
        if ($this->context->hasScopes(['pancek.answer'])) {
            if ($this->formulir->status == PancekFormulir::STATUS_NEED_TO_REVIEW) {
                $flow = $this->getFormulirFlow();
                if ($flow === self::FLOW_BK) {
                    $this->handleFormulirSubmitNotificationBK();
                } elseif ($flow === self::FLOW_BC) {
                    $this->handleFormulirSubmitNotificationBC();
                } else {
                    $this->handleFormulirSubmitNotificationKPK();
                }
            }

            if ($formulir->isDownloadAvailable()) {
                $userId = $this->formulir->instansi->user->um_id;
                $emails = UmUser::emailsByUmIds([$userId]);
                $senderUserId = $this->formulir->instansi->user->um_id;
                $body = ", Anda telah dapat mencetak Formulir Badan Usaha " . $this->formulir->instansi->nama;
                $action = NotificationHelper::ACTION_PANCEK;
                $actionId = null;
                $clickAction = self::ACTION_FORM;
                $category = NotificationHelper::CATEGORY_PANCEK_FORM;
                $bodyEn = $body;
                NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
                
                $this->handleSendNotificiationAsEmail($emails, "Kamu telah dapat mencetak Formulir Badan Usaha " . $this->formulir->instansi->nama);
            }
        }
    }

    public function handleAssignmentNotification($verifikatorId)
    {
        $userId = $verifikatorId;
        $emails = UmUser::emailsByUmIds([$userId]);
        $senderUserId = $this->context->shared->user->um_id;
        $body = "memberikan assignment Formulir baru untuk Anda.";
        $action = NotificationHelper::ACTION_PANCEK;
        $actionId = null;
        $clickAction = self::ACTION_REKAPITULASI;
        $category = NotificationHelper::CATEGORY_PANCEK_REKAPITULASI;
        $bodyEn = $body;
        NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
        
        $this->handleSendNotificiationAsEmail($emails, "Kamu menerima assignment Formulir baru.");
    }

    public function handleAssignorNotification($assignorId)
    {
        $userId = $assignorId;
        $emails = UmUser::emailsByUmIds([$userId]);
        $senderUserId = $this->context->shared->user->um_id;
        $body = "memberikan assignment KPPBC baru untuk Anda. Mohon lakukan proses assignment ke Verifikator.";
        $action = NotificationHelper::ACTION_PANCEK;
        $actionId = null;
        $clickAction = self::ACTION_ASSIGN;
        $category = NotificationHelper::CATEGORY_PANCEK_ASSIGN;
        $bodyEn = $body;
        NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
        
        $this->handleSendNotificiationAsEmail($emails, "Kamu menerima assignment KPPBC baru. Mohon lakukan proses assignment ke Verifikator.");
    }

    public function handleFormulirVerifyNotification(PancekFormulir $formulir)
    {
        $this->formulir = $formulir;

        $userId = $this->formulir->instansi->user->um_id;
        $emails = [$this->formulir->instansi->user->umUser->email];
        $senderUserId = $this->context->shared->user->um_id;
        $action = NotificationHelper::ACTION_PANCEK;
        $actionId = null;
        $clickAction = self::ACTION_FORM;
        $category = NotificationHelper::CATEGORY_PANCEK_FORM;
        $isDownloadVerifiedAvailable = $formulir->isDownloadVerifiedAvailable();
        if ($isDownloadVerifiedAvailable) {
            $body = ", Anda telah dapat mencetak Formulir Badan Usaha " . $this->formulir->instansi->nama . " yang telah diverifikasi.";
            $bodyEn = $body;
            NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
        } else {
            $body = "telah melakukan verifikasi Formulir Anda.";
            $bodyEn = $body;
            NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
        }
        $this->sendMailFormulirStatusChange($this->formulir, $isDownloadVerifiedAvailable);
    }

    public function sendMailFormulirStatusChange(PancekFormulir $formulir, $isDownloadVerifiedAvailable = false)
    {
        $instansi = $formulir->instansi;
        $subject = "[JAGA] Perubahan Status Formulir";

        $h = function ($v) {
            return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
        };

        $message  = "Hi Sahabat JAGA, terima kasih telah menggunakan Aplikasi JAGA.";
        $message .= "<br>Kamu menerima email ini karena adanya perubahan status formulir Pancek Badan Usaha kamu.";
        if ($isDownloadVerifiedAvailable) {
            $message .= " Kamu telah dapat mencetak Formulir Badan Usaha yang telah diverifikasi.";
        }
        $message .= "<br><br>";

        $message .= '<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse">';
        $message .= '  <thead>';
        $message .= '    <tr><th colspan="2" align="left">Informasi Formulir Pancek</th></tr>';
        $message .= '  </thead>';
        $message .= '  <tbody>';
        $message .= '    <tr><td>Nama Badan Usaha</td><td>' . $h($instansi->nama ?? '') . '</td></tr>';
        $message .= '    <tr><td>NPWP</td><td>' . $h($instansi->npwp ?? '') . '</td></tr>';
        $message .= '    <tr><td>Telepon</td><td>' . $h($instansi->telepon ?? '') . '</td></tr>';
        $message .= '    <tr><td>Status Formulir</td><td>' . $h($formulir->status ?? '') . '</td></tr>';
        $message .= '  </tbody>';
        $message .= '</table>';

        if ($formulir->status == PancekFormulir::STATUS_REVIEWED && !$formulir->isDownloadVerifiedAvailable()) {
            $empties = [];
            $rejects = [];
            foreach ($formulir->answers as $answer) {
                if (count($answer->attachments) < 1) {
                    $empties[] = $answer;
                } elseif ($answer->verify_status == PancekAnswer::VERIFY_STATUS_DIKEMBALIKAN) {
                    $rejects[] = $answer;
                }
            }

            if (!empty($empties)) {
                $message .= "<br><br>Isian Formulir yang belum diisi:<br><br>";
                $message .= '<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse">';
                $message .= '<thead><tr><th>Kode</th><th>Indikator</th></tr></thead><tbody>';

                foreach ($empties as $answer) {
                    $code  = htmlspecialchars(($answer->komponenIndikator->code ?? ''), ENT_QUOTES, 'UTF-8');
                    $label = htmlspecialchars(strip_tags(($answer->komponenIndikator->label ?? '')), ENT_QUOTES, 'UTF-8');

                    $message .= "<tr><td>{$code}</td><td>{$label}</td></tr>";
                }

                $message .= '</tbody></table>';
            }

            if (!empty($rejects)) {
                $message .= "<br><br>Isian Formulir yang ditolak:<br><br>";
                $message .= '<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse">';
                $message .= '<thead><tr><th>Kode</th><th>Indikator</th></tr></thead><tbody>';

                foreach ($rejects as $answer) {
                    $code  = htmlspecialchars(($answer->komponenIndikator->code ?? ''), ENT_QUOTES, 'UTF-8');
                    $label = htmlspecialchars(strip_tags(($answer->komponenIndikator->label ?? '')), ENT_QUOTES, 'UTF-8');

                    $message .= "<tr><td>{$code}</td><td>{$label}</td></tr>";
                }

                $message .= '</tbody></table>';
            }
        }

        $message .= "<br><br>Akses JAGA dan bantu kami untuk Cegah Korupsi dari Ujung Jari."
                . "<br><br>Perhatian: E-mail ini (termasuk seluruh lampirannya, bila ada) dikirim otomatis oleh aplikasi dan hanya ditujukan kepada penerima yang tercantum di atas. Jika Anda bukan penerima yang dituju, maka Anda tidak diperkenankan untuk memanfaatkan, menyebarkan, mendistribusikan, atau menggandakan e-mail ini beserta seluruh lampirannya. Mohon untuk tidak membalas email ini."
        ;
        
        $this->handleSendEmail($instansi->email, $subject, $message, true);
    }

    public function getFormulirFlow()
    {
        $flow = null;
        if (!empty($this->formulir)) {
            $ceklisKepentingan = $this->formulir->instansi->ceklis_kepentingan;
            if ($ceklisKepentingan === self::CEKLIS_KEPENTINGAN_BK) {
                $flow = self::FLOW_BK;
            } elseif ($ceklisKepentingan === self::CEKLIST_KEPENTINGAN_BC) {
                $flow = self::FLOW_BC;
            }
        }
        return $flow;
    }

    public function getInstansiVerifikatorByInstansiId($instansiId)
    {
        return $this->context->rawQuery("
                SELECT iv.user_id, iv.instansi_id, u.email
                FROM jaga.pancek_instansi_verifikator iv
                LEFT JOIN jaga.pancek_user_access ua ON ua.user_id = iv.user_id AND ua.deleted_at IS NULL
                LEFT JOIN jaga.um_user u ON u.um_id = ua.user_id
                WHERE iv.deleted_at IS NULL AND (ua.end_date IS NULL OR now() < ua.end_date) AND iv.instansi_id = :instansi_id
            ", ['instansi_id' => $instansiId]);
    }

    public function getAssignorsBK()
    {
        return $this->context->rawQuery("
            SELECT u.um_id, u.um_user_name, u.email
            FROM jaga.um_user u
            LEFT JOIN jaga.users_roles ur ON ur.user_id = u.um_id
            LEFT JOIN jaga.roles_scopes rs ON rs.role_id = ur.role_id
            LEFT JOIN jaga.scopes s ON s.id = rs.scope_id
            WHERE s.name = 'pancek.bk.assign';
        ");
    }

    public function getAssignorsBC()
    {
        return $this->context->rawQuery(
            "SELECT u.um_id, u.um_user_name, u.email
            FROM jaga.um_user u
            LEFT JOIN jaga.users_roles ur ON ur.user_id = u.um_id
            LEFT JOIN jaga.roles_scopes rs ON rs.role_id = ur.role_id
            LEFT JOIN jaga.scopes s ON s.id = rs.scope_id
            LEFT JOIN jaga.pancek_kppbc_user ku ON ku.um_id = u.um_id
            WHERE s.name = 'pancek.kppbc.assignor' AND ku.user_type = 'ASSIGNOR' AND ku.deleted_at IS NULL AND ku.kppbc_id = ".$this->formulir->instansi->kppbc_id.";"
        );
    }

    public function getAdminBC()
    {
        return $this->context->rawQuery(
            "SELECT u.um_id, u.um_user_name, u.email
            FROM jaga.um_user u
            LEFT JOIN jaga.users_roles ur ON ur.user_id = u.um_id
            LEFT JOIN jaga.roles_scopes rs ON rs.role_id = ur.role_id
            LEFT JOIN jaga.scopes s ON s.id = rs.scope_id
            WHERE s.name = 'pancek.kppbc.admin';"
        );
    }

    public function getAdminPancek()
    {
        return $this->context->rawQuery("
            SELECT u.um_id, u.um_user_name, u.email
            FROM jaga.um_user u
            LEFT JOIN jaga.users_roles ur ON ur.user_id = u.um_id
            LEFT JOIN jaga.roles_scopes rs ON rs.role_id = ur.role_id
            LEFT JOIN jaga.scopes s ON s.id = rs.scope_id
            WHERE s.name = 'pancek.admin';
        ");
    }

    public function logFormulirCreate(PancekFormulir $formulir)
    {
        $log = new PancekFormulirLog();
        return $log->doLogging($formulir, $this->context->shared->user->um_id, PancekFormulirLog::DESC_CREATE);
    }

    public function logFormulirSubmit(PancekFormulir $formulir)
    {
        $log = new PancekFormulirLog();
        switch ($formulir->status) {
            case PancekFormulir::STATUS_DRAFT:
                return $log->doLogging($formulir, $this->context->shared->user->um_id, PancekFormulirLog::DESC_DRAFT);
            case PancekFormulir::STATUS_NEED_TO_REVIEW:
                return $log->doLogging($formulir, $this->context->shared->user->um_id, PancekFormulirLog::DESC_NEED_REVIEW);
            case PancekFormulir::STATUS_REVIEWED:
                return $log->doLogging($formulir, $this->context->shared->user->um_id, PancekFormulirLog::DESC_REVIEWED);
            case PancekFormulir::STATUS_VERIFIED:
                return $log->doLogging($formulir, $this->context->shared->user->um_id, PancekFormulirLog::DESC_VERIFIED);
            default:
                break;
        }
    }

    public function logAnswerSubmit(PancekAnswer $answer)
    {
        $log = new PancekAnswerLog();
        switch ($answer->verify_status) {
            case PancekAnswer::VERIFY_STATUS_DIKEMBALIKAN:
                return $log->doLogging($answer, $this->context->shared->user->um_id, PancekAnswerLog::DESC_REJECTED);
            case PancekAnswer::VERIFY_STATUS_REVISED:
                return $log->doLogging($answer, $this->context->shared->user->um_id, PancekAnswerLog::DESC_REVISED);
            default:
                break;
        }
    }

    private function handleFormulirSubmitNotificationBK()
    {
        $assigned = $this->getInstansiVerifikatorByInstansiId($this->formulir->instansi_id);
        $emails = [];
        if (empty($assigned)) {
            $assignors = $this->getAssignorsBK();
            $receiverIds = [];
            foreach ($assignors as $assignor) {
                $receiverIds[] = $assignor['um_id'];
                $emails[] = $assignor['email'];
            }
            $senderUserId = $this->formulir->instansi->user->um_id;
            $body = "dari Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses assignment ke Verifikator.";
            $action = NotificationHelper::ACTION_PANCEK;
            $actionId = null;
            $clickAction = self::ACTION_ASSIGN;
            $category = NotificationHelper::CATEGORY_PANCEK_ASSIGN;
            $bodyEn = $body;
            NotificationHelper::batchSend($receiverIds, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
            $mailBody = "Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses assignment ke Verifikator.";
        } else {
            $userId = $assigned[0]['user_id'];
            $emails[] = $assigned[0]['email'];
            $senderUserId = $this->formulir->instansi->user->um_id;
            $body = "dari Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi.";
            $action = NotificationHelper::ACTION_PANCEK;
            $actionId = "?instansi_id=" . $this->formulir->instansi_id;
            $clickAction = self::ACTION_VERIFY . $actionId;
            $category = NotificationHelper::CATEGORY_PANCEK_VERIFY;
            $bodyEn = $body;
            NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
            $mailBody = "Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses verifikasi.";
        }

        $this->handleSendNotificiationAsEmail($emails, $mailBody);
    }

    private function handleFormulirSubmitNotificationBC()
    {
        $assigned = $this->getInstansiVerifikatorByInstansiId($this->formulir->instansi_id);
        $emails = [];
        if (empty($assigned)) {
            $receiverIds = [];
            $assignors = $this->getAssignorsBC();
            if (empty($assignors)) {
                $admins = $this->getAdminBC();
                foreach ($admins as $admin) {
                    $receiverIds[] = $admin['um_id'];
                    $emails[] = $admin['email'];
                }
                $body = "dari Badan Usaha " . $this->formulir->instansi->nama . " " . $this->formulir->instansi->kppbc->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses assignment KPPBC ke Assignor.";
                $actionId = "/" . $this->formulir->instansi->kppbc->id;
                $clickAction = self::ACTION_ASSIGN_KPPBC;
                $category = NotificationHelper::CATEGORY_PANCEK_ASSIGN_KPPBC;
                $mailBody = "Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses assignment KPPBC ke Assignor.";
            } else {
                foreach ($assignors as $assignor) {
                    $receiverIds[] = $assignor['um_id'];
                    $emails[] = $assignor['email'];
                }
                $body = "dari Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses assignment ke Verifikator.";
                $actionId = null;
                $clickAction = self::ACTION_ASSIGN;
                $category = NotificationHelper::CATEGORY_PANCEK_ASSIGN;
                $mailBody = "Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses assignment ke Verifikator.";
            }
            $senderUserId = $this->formulir->instansi->user->um_id;
            $action = NotificationHelper::ACTION_PANCEK;
            $bodyEn = $body;
            NotificationHelper::batchSend($receiverIds, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
        } else {
            $userId = $this->formulir->kppbc_um_id;
            $emails = UmUser::emailsByUmIds([$userId]);
            $senderUserId = $this->formulir->instansi->user->um_id;
            $body = "dari Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi.";
            $action = NotificationHelper::ACTION_PANCEK;
            $actionId = "?instansi_id=" . $this->formulir->instansi_id;
            $clickAction = self::ACTION_VERIFY . $actionId;
            $category = NotificationHelper::CATEGORY_PANCEK_VERIFY;
            $bodyEn = $body;
            NotificationHelper::send($userId, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
            $mailBody = "Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses verifikasi.";
        }

        $this->handleSendNotificiationAsEmail($emails, $mailBody);
    }

    private function handleFormulirSubmitNotificationKPK()
    {
        $admins = $this->getAdminPancek();
        $receiverIds = [];
        $emails = [];
        foreach ($admins as $admin) {
            $receiverIds[] = $admin['um_id'];
            $emails[] = $admin['email'];
        }
        $senderUserId = $this->formulir->instansi->user->um_id;
        $body = "dari Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi.";
        $action = NotificationHelper::ACTION_PANCEK;
        $actionId = "?instansi_id=" . $this->formulir->instansi_id;
        $clickAction = self::ACTION_VERIFY . $actionId;
        $category = NotificationHelper::CATEGORY_PANCEK_VERIFY;
        $bodyEn = $body;
        NotificationHelper::batchSend($receiverIds, $senderUserId, $body, $action, $actionId, $clickAction, $category, $bodyEn);
        $mailBody = "Badan Usaha " . $this->formulir->instansi->nama . " telah melakukan submit formulir untuk diverifikasi. Mohon lakukan proses verifikasi.";
        
        $this->handleSendNotificiationAsEmail($emails, $mailBody);
    }

    private function handleSendEmail($email, $subject, $message, $isHTML = false)
    {
        $mail = new MailHelper($this->context->config["mail_config"]);
        $mail->queue($email, $subject, $message, $isHTML);
    }

    private function handleSendNotificiationAsEmail(array $emails, $body)
    {
        $subject = "[JAGA] PanCEK";
        $message = "Hi Sahabat JAGA, terima kasih telah menggunakan Aplikasi JAGA."
            . "\n\nKamu menerima email ini karena " . $body
        ;

        $message .= "\n\nAkses JAGA dan bantu kami untuk Cegah Korupsi dari Ujung Jari."
            . "\n\nPerhatian: E-mail ini (termasuk seluruh lampirannya, bila ada) dikirim otomatis oleh aplikasi dan hanya ditujukan kepada penerima yang tercantum di atas. Jika Anda bukan penerima yang dituju, maka Anda tidak diperkenankan untuk memanfaatkan, menyebarkan, mendistribusikan, atau menggandakan e-mail ini beserta seluruh lampirannya. Mohon untuk tidak membalas email ini."
        ;

        foreach ($emails as $email) {
            $this->handleSendEmail($email, $subject, $message);
        }
    }
}