<?php

class PancekAnswerController extends BaseController
{
    public function submit()
    {
        $this->checkOneOfScopes(['pancek.admin', 'pancek.answer']);
        $rawParams = $this->request->getJsonRawBody(true);
        if ($this->hasScopes(['pancek.answer'])) {
            $pancekUser = PancekUser::findByUmId($this->shared->user->um_id);
            $rawParams['instansi_id'] = $pancekUser['instansi']['id'];
        }
        $params = $this->validate(
            $rawParams,
            [
                'answer_id' => ['validators' => ['digit', 'required']],
                'attachments' => ['validators' => []]
            ]
        );

        /** @var $answer PancekAnswer */
        $answer = PancekAnswer::findFirst($params['answer_id']);
        if (!$answer) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "Item formulir tidak ditemukan");
        }

        /** @var $formulir PancekFormulir */
        $formulir = PancekFormulir::findFirst([
            'conditions' => 'id = :formulir_id: AND deleted_at IS NULL',
            'bind' => [
                'formulir_id' => $answer->formulir_id
            ]
        ]);

        if (!$formulir) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Formulir tidak ditemukan");
        }
        if ($formulir->isExpired()) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Formulir telah expired");
        }
        if ($formulir->isExceedRevisionLimit()) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Formulir telah melebihi batas revisi");
        }

        try{
            $this->db->begin();
            $attachment_ids = [];
            if (!empty($params['attachments'])) {
                foreach ($params['attachments'] as $attachment) {
                    $this->validate(
                        $attachment,
                        [
                            "attachment_id" => ['validators' => ['required', 'digit']]
                        ]
                    );
                    $attachmentRecord = Attachments::findFirst($attachment['attachment_id']);
                    if ($attachmentRecord && empty($attachmentRecord->deleted_at)) {
                        $attachmentRecord->status = Attachments::STATUS_REFERRED;
                        $attachmentRecord->referer = Attachments::REFERER_PANCEK_ANSWER;
                        if (!$attachmentRecord->save()) {
                            $errors = $attachmentRecord->getMessages();
                            $error_messages = [];

                            foreach ($errors as $key => $error) {
                                $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
                            }

                            throw new ValidationException($error_messages);
                        }

                        /** @var $answerAttachment PancekAnswerAttachment */
                        $answerAttachment = PancekAnswerAttachment::firstOrCreate("attachment_id = " . $attachmentRecord->id);
                        $answerAttachment->answer_id = $answer->id;
                        $answerAttachment->attachment_id = $attachmentRecord->id;
                        if ($answerAttachment->isNewRecord()) {
                            $answerAttachment->created_at = DateHelper::getNowTimezoned();
                        } else {
                            $answerAttachment->updated_at = DateHelper::getNowTimezoned();
                        }
                        if (!$answerAttachment->save()) {
                            $errors = $answerAttachment->getMessages();
                            $error_messages = [];

                            foreach ($errors as $key => $error) {
                                $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
                            }

                            throw new ValidationException($error_messages);
                        }
                        array_push($attachment_ids, $answerAttachment->attachment_id);
                    } else {
                        throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Attachment [#" . $attachment['attachment_id'] . "] tidak ditemukan");
                    }
                }
            }
            $answer->updated_at = date("Y-m-d H:i:s");
            if (!$answer->save()) {
                $errors = $answer->getMessages();
                $error_messages = [];

                foreach ($errors as $key => $error) {
                    $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
                }

                throw new ValidationException($error_messages);
            } else {
                $answer->syncAttachments($attachment_ids);
            }

            $res = $formulir->getForm();
            $this->db->commit();
            return new SimpleResponse($res);
        } catch (\Exception $e) {
            $this->db->rollback();
            throw $e;
        }
    }

    public function comment($id) {
        $this->checkOneOfScopes(['pancek.admin', 'pancek.verify']);

        //todo hanya bisa komen isian dari formulir dengan status NEED_TO_REVIEW?
        $payload = $this->request->getJsonRawBody(true);
        $payload = $this->validate($payload, [
            "keterangan" => ["validators" => ["required"]]
        ]);

        /** @var PancekAnswer $answer */
        $answer = PancekAnswer::findFirst($id);
        if (!$answer) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "Isian formulir tidak ditemukan.");
        }

        $answer->updated_at = DateHelper::getNowTimezoned();
        $answer->keterangan = $payload["keterangan"];
        if (!$answer->save()) {
            $errors = $answer->getMessages();
            $error_messages = [];

            foreach ($errors as $key => $error) {
                $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
            }

            throw new ValidationException($error_messages);
        }

        return new SimpleResponse($answer);
    }

    public function accept($id) {
        return $this->verify($id, PancekAnswer::VERIFY_STATUS_DISETUJUI);
    }

    public function reject($id) {
        return $this->verify($id, PancekAnswer::VERIFY_STATUS_DIKEMBALIKAN);
    }

    private function verify($id, $verifyStatus) {

        $this->checkOneOfScopes(['pancek.verify', 'pancek.kppbc.verify', 'pancek.bk.verify']);

        $payload = $this->request->getJsonRawBody(true);
        $payload = $this->validate($payload, [
            "keterangan" => ["validators" => ["required"]]
        ]);

        try {
            $this->db->begin();
            $answer = PancekAnswer::findFirst($id);
            if (!$answer) {
                throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "Isian formulir tidak ditemukan.");
            }

            $formulirPancek = $answer->formulir;
            $instansiPancek = $formulirPancek->instansi;
            if(!$instansiPancek) {
                throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "Instansi Pancek tidak ditemukan");
            }

            if ($this->hasScopes(['pancek.kppbc.verify']) && !$this->hasScopes(['pancek.verify'])) {
                $this->validateAksesUserKppbc($instansiPancek, $formulirPancek);
            }

            if (count($answer->attachments) < 1) {
                throw new CustomErrorException(BaseResponse::INVALID_ACTION, "File pada Komponen Indikator belum diunggah.");
            }

            if ($answer->verify_status == PancekAnswer::VERIFY_STATUS_DISETUJUI) {
                throw new CustomErrorException(BaseResponse::INVALID_ACTION, "Komponen Indikator sudah diverifikasi.");
            }

            if ($answer->verify_status == PancekAnswer::VERIFY_STATUS_DIKEMBALIKAN) {
                throw new CustomErrorException(BaseResponse::INVALID_ACTION, "Komponen Indikator belum direvisi.");
            }

            if($formulirPancek->status == PancekFormulir::STATUS_NEW || $formulirPancek->status == PancekFormulir::STATUS_DRAFT) {
                throw new CustomErrorException(BaseResponse::DATA_NOT_AVAILABLE, "Formulir belum diajukan untuk verifikasi");
            }

            if($formulirPancek->status == PancekFormulir::STATUS_REVIEWED || $formulirPancek->status == PancekFormulir::STATUS_VERIFIED) {
                throw new CustomErrorException(BaseResponse::DATA_NOT_AVAILABLE, "Formulir sudah selesai diverifikasi");
            }

            $nowDateTime = DateHelper::getNowDateTimeTimeZoned();
            $nowFormatted = DateHelper::formatDateTime($nowDateTime);

            $answer->updated_at = $nowFormatted;
            $answer->keterangan = $payload["keterangan"];
            $answer->verify_status = $verifyStatus;
            $answer->verified_at = $nowFormatted;
            $answer->verified_by = $this->userID;

            if (!$answer->save()) {
                $errors = $answer->getMessages();
                $error_messages = [];

                foreach ($errors as $key => $error) {
                    $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
                }

                throw new ValidationException($error_messages);
            }

            $pancekService = new PancekService($this);
            $pancekService->logAnswerSubmit($answer);

            if($formulirPancek->status == PancekFormulir::STATUS_NEED_TO_REVIEW) {
                if($this->hasScopes(['pancek.kppbc.verify']) && !$this->hasScopes(['pancek.verify'])) {
                    $slaDays = getenv('PANCEK_SLA_VERIF_KPPBC') !== false ? getenv('PANCEK_SLA_VERIF_KPPBC') : 14;
                    $nowPlusSlaDateTime = clone $nowDateTime;
                    $nowPlusSlaDateTime->modify('+' . $slaDays . ' days');
                    $nowPlusSlaFormatted = DateHelper::formatDateTime($nowPlusSlaDateTime);

                    $formulirPancek->kppbc_um_id = $this->userID;
                    $formulirPancek->kppbc_verify_start_date = $nowFormatted;
                    $formulirPancek->kppbc_verify_end_date = $nowPlusSlaFormatted;
                }
                $formulirPancek->status = PancekFormulir::STATUS_REVIEW_IN_PROGRESS;
                $formulirPancek->save();
            }

            $this->saveVerifyLog($id, $this->userID, $payload["keterangan"], $verifyStatus);


            $this->db->commit();
            return new SimpleResponse($answer);
        }
        catch (CustomErrorException $exception) {
            $this->db->rollback();
            throw new CustomErrorException($exception->getStatusCode(), $exception->getMessages());
        }
        catch (Exception $exception) {
            $this->db->rollback();
            throw $exception;
        }
    }

    private function validateAksesUserKppbc($instansiPancek, $formulirPancek)
    {
        $kppbcUser = PancekKppbcUser::findFirst([
            'conditions' => 'um_id = :um_id: AND kppbc_id = :kppbc_id: AND deleted_at IS NULL',
            'bind' => [
                'um_id' => $this->userID,
                'kppbc_id' => $instansiPancek->kppbc_id
            ]
        ]);

        if(!$kppbcUser) {
            throw new CustomErrorException(BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION, 'User is not allowed to perform this action');
        }

        if (!PancekInstansiVerifikator::findInstansiByIdAndAccess($formulirPancek->instansi_id, $this->userID, $this)) {
            throw new CustomErrorException(BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION, 'Anda tidak ditugaskan pada Badan Usaha ini atau akses verifikasi Anda telah habis');
        }

        /*if($formulirPancek->kppbc_um_id != null) {
            if($formulirPancek->kppbc_um_id != $this->userID) {
                throw new CustomErrorException(BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION, "Anda tidak ditugaskan pada Badan Usaha ini");
            }

            if($formulirPancek->kppbc_verify_end_date != null) {
                $now = new DateTime(DateHelper::getNowTimezoned());
                $verifyEndDate = new DateTime($formulirPancek->kppbc_verify_end_date);
                if ($now > $verifyEndDate) {
                    throw new CustomErrorException(BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION, "Akses verifikasi sudah habis (berakhir pada " . $formulirPancek->kppbc_verify_end_date . ")");
                }
            }
        }
        else {
            throw new CustomErrorException(BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION, "Anda tidak ditugaskan pada Badan Usaha ini");
        }*/
    }

    private function saveVerifyLog($id, $userID, $keterangan, $verifyStatus)
    {
        try {
            $answerLog = new PancekAnswerLogVerifikasi();
            $answerLog->answer_id = $id;
            $answerLog->um_id = $userID;
            $answerLog->komentar = $keterangan;
            $answerLog->verify_status = $verifyStatus;
            $answerLog->save();
        }
        catch (Exception $e) {

        }
    }

    private function getCountVerifiedStatusOnAllAnswers($formulirPancek)
    {
        $q = "
            SELECT 
                COUNT(id) AS total_answer,
                COUNT(id) FILTER (WHERE verify_status = 'ACCEPTED') AS total_accepted
            FROM
            	jaga.pancek_answer 
            WHERE
            	formulir_id = :formulir_id;
	    ";
        
        $bind = [
            'formulir_id' => $formulirPancek->id
        ];
        
        return $this->rawQuery($q, $bind)[0];
    }

    private function verifyingFormulir($countVerifyStatusAnswers, $formulirPancek, $instansiPancek, $nowFormatted)
    {
        if($countVerifyStatusAnswers['total_answer'] == $countVerifyStatusAnswers['total_accepted']) {
            $formulirPancek->status = PancekFormulir::STATUS_VERIFIED;
            $formulirPancek->updated_at = $nowFormatted;
            $formulirPancek->verified_at = $nowFormatted;
            $formulirPancek->verified_by = $this->userID;
            $formulirPancek->save();
        }
        else {
            if($formulirPancek->status == PancekFormulir::STATUS_NEW || $formulirPancek->status == PancekFormulir::STATUS_DRAFT || $formulirPancek->status == PancekFormulir::STATUS_NEED_TO_REVIEW) {
                $formulirPancek->status = PancekFormulir::STATUS_REVIEWED;
                $formulirPancek->updated_at = $nowFormatted;
                $formulirPancek->reviewed_at = $nowFormatted;
                $formulirPancek->reviewed_by = $this->userID;
                $formulirPancek->save();
            }
        }
    }
}
