<?php

//namespace Jaga\Controllers;
use Phalcon\Mvc\Model\Query;
use Jaga\Models\PAK\PAKQuestionnaire;
use Jaga\Models\PAK\PAKJenisDokumenQuestionnaire;
use Jaga\Models\PAK\PAKImplementasi;
use Jaga\Models\PAK\PAKImplementasiVerifikasi;
use Jaga\Models\PAK\PAKImplementasiAttachment;


class PAKImplementasiController extends BaseController
{
    protected $attachmentFolder;

    public function onConstruct()
    {
        parent::onConstruct();
        $this->checkIsAuthenticated();
        $this->attachmentFolder = 'pak-verifikasi-implementasi-attachment' . DIRECTORY_SEPARATOR;
    }

    public function index()
    {
        $this->checkScopes(['pak.view.implementasi']);

        $params = $this->validateIndexRequest($this->request);

        if (isset($params['trashed']) && $params['trashed'] == true) {

            $this->checkScopes(['pak.manage.questionnaire']);

            $conditions = "deleted_at IS NOT NULL";
        } else {
            $conditions = "deleted_at IS NULL";
        }

        if (isset($params['status']) && $params['status'] > 0) {
            $conditions .= " AND status = " . $params['status'];
        }

        if (!empty($params['year'])) {
            $year = (int)$params['year'];
            $conditions .= "  AND created_at >= to_date('".$year."', 'YYYY') AND created_at < to_date('". ($year+1) ."', 'YYYY') ";
        }

        if ($this->hasRole('user_dinas_pak') && !$this->hasRole('admin_pak')) {
            $instansi_id = $this->shared->user->id_instansi;
            $conditions .= " AND instansi_id = " . $instansi_id;
        }
        elseif (!empty($params['dinas']) &&
            $this->hasOneOfRoles(['admin_pak','verifikator_pak','observer_pak'])
        ) {
            $query = new Query(
                "SELECT id, nama FROM Instansi where nama ILIKE '%".$params['dinas']."%'",
                $this->getDI()
            );

            // Execute the query returning a result if any
            $instansi = $query->execute();

            $ids = '(';
            if (count($instansi) > 0) {
                foreach ($instansi as $key => $i) {
                    $ids .= ($key>0) ? ','.$i['id'] : $i['id'];
                }
            } else {
                $ids .= '0';
            }

            $ids .= ')';

            $conditions .= " AND instansi_id IN " . $ids;

        }

        $order_by = (!empty($params['order_by']) && $params['order_by'] != 'means') ? $params['order_by'] : 'id';
        $sort = !empty($params['sort']) ? $params['sort'] : 'desc';

        $all = PAKImplementasi::find(['conditions' => $conditions]);
        $total_record = count($all);
        $rows = PAKImplementasi::find([
                    'conditions' => $conditions,
                    'limit' => $params['limit'],
                    'offset' => $params['offset'],
                    'order' =>  $order_by . ' ' . $sort,
        ]);

        $result = [];
        if(!empty($rows)) {
            foreach ($rows as $key => $row) {
                $item = $row->getDetail(false);
                array_push($result, $item);
            }
        }

        /*if($params['order_by'] == 'means') {
            if ($sort == 'asc') {
                usort($result, function($a, $b) {
                    return $a['verification_means'] <=> $b['verification_means'];
                });
            }
            else {
                usort($result, function($a, $b) {
                    return $b['verification_means'] <=> $a['verification_means'];
                });
            }
        }*/

        return new PaginatedResponse(
            $result,
            $total_record,
            $params['limit'],
            $params['offset']
        );
    }

    protected function validateIndexRequest($request)
    {
        $params = $request->get();
        $params['limit'] = $request->get('limit', null, 8);
        $params['offset'] = $request->get('offset', null, 0);
        $params['keyword'] = $request->get('keyword', null, '');
        $params['order_by'] = $request->get('order_by', null, 'id');
        $params['sort'] = $request->get('sort', null, 'desc');
        $params['status'] = $request->get('status', null, -1);

        $allowed_order_by = ['id', 'instansi_id'/*, 'means'*/];
        $allowed_sort = ['asc', 'desc'];
        $rules = [
            'dinas' => ['validators' => []],
            'year' => ['validators' => ['digit']],
            'limit' => ['validators' => ['digit']],
            'offset' => ['validators' => ['digit']],
            'status' => ['validators' => ['digit']],
            'keyword' => ['validators' => []],
            'order_by' => ['validators' =>  [[
                'name' => 'inclusion_in',
                'params' => $allowed_order_by
            ]]],
            'sort' => ['validators' =>  [[
                'name' => 'inclusion_in',
                'params' => $allowed_sort
            ]]]
        ];

        $validatedParams = $this->validate($params, $rules);

        return $validatedParams;
    }

    public function view($id)
    {
        $this->checkScopes(['pak.view.implementasi']);

        $model = PAKImplementasi::findOrFail($id);

        // menyesuaikan dengan list regulasi di dashboard
        // 1. regulasi pusat bisa dilihat oleh semua instansi
        // 2. regulasi pemda tingkat 1 hanya bisa dilihat oleh instansi provinsi tsb
        // 3. regulasi pemda tingkat 2 hanya bisa dilihat oleh instansi kab/kota atau provinsi tsb
        $instansiUser = $this->shared->user->instansi;
        $instansiModel = $model->instansi;
        if ($this->hasRole('user_dinas_pak') && ($instansiModel && $instansiModel->id_tipe != 3)) {
            if (
                ($instansiUser && $instansiUser->id_tipe == 1 && $instansiUser->id_provinsi != $instansiModel->id_provinsi) ||
                ($instansiUser && $instansiUser->id_tipe == 2 && $instansiUser->id_kota_kabupaten != $instansiModel->id_kota_kabupaten)
            ) {
                throw new CustomErrorException(
                    BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION,
                    'User is not allowed to perform this action'
                );
            }
        }

        $result = $model->getDetail();

        return new CollectionPaginatedResponse([$result]);
    }

    public function uploadAttachment()
    {
        try {
            $this->checkScopes(['pak.manage.implementasi']);
        }
        catch (CustomErrorException $e) {
            if (!$this->hasRole('admin_pak')) {
                throw $e;
            }
        }

        $postRequest = $this->request->getPost();

        $validatedRequest = $this->validate($postRequest, [
            'keterangan' => ['validators' => []],
            'metadata' => ['validators' => []]
        ]);

        $minioService = $this->minio;
        $service = new AttachmentService($this->shared, $minioService);
        $validationConfig = [
            'allowed-types' => [
                "application/pdf",
                "application/msword",
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                "application/vnd.ms-office",
            ],
        ];
        $attachmentConfig = [
            'tipe' => Attachments::TIPE_PUBLIC,
        ];

        if ($minioService->isSecondaryS3Available()) {
            $attachments = $service->uploadUsingSecondaryS3(
                getenv("FILESYSTEM_CLOUD"),
                $validationConfig,
                $attachmentConfig,
                $this->request,
                $this->attachmentFolder
            );
        }
        else {
            $attachments = $service->upload(
                getenv("FILESYSTEM_CLOUD"),
                $validationConfig,
                $attachmentConfig,
                $this->request,
                $this->attachmentFolder
            );
        }

        return new CollectionPaginatedResponse($attachments);
    }

    public function presignedUrlUpload()
    {
        try {
            $this->checkScopes(['pak.manage.implementasi']);
        }
        catch (CustomErrorException $e) {
            if (!$this->hasRole('admin_pak')) {
                throw $e;
            }
        }

        $request = $this->request->get();
        $validatedRequest = $this->validate($request, [
            'amount' => ['validators' => ['required', 'digit']],
        ]);

        $amount = (int) $validatedRequest['amount'];
        $subFolder = $this->attachmentFolder;
        $service = new AttachmentService($this->shared, $this->minio);
        $presignedUrls = [];
        for ($i = 0; $i < $amount; $i++) {
            $presignedUrls[] = $service->presignedUrlUpload($subFolder);
        }

        return new CollectionPaginatedResponse($presignedUrls);
    }

    public function downloadAttachment($uuid)
    {
        $this->checkScopes(['pak.view.implementasi']);

        /** @var Attachments $attachment */
        $attachment = Attachments::findOrFail(
            [
                "uuid = :uuid:",
                "bind" => [
                    "uuid" => $uuid
                ]
            ]
        );

        if (!empty($attachment)) {
            if (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::MINIO) {
                /** @var MinioService $minioService */
                $minioService = $this->minio;
                $filename = $attachment->filename;
                $filekey = 'users_profpic' . DIRECTORY_SEPARATOR . $this->attachmentFolder . DIRECTORY_SEPARATOR . $uuid;

                $url = $attachment->validPresignedUrl();
                if (!$url) {
                    $url = $minioService->checkAndDownloadPublicWithLongExpDuration(
                        LogAttachments::PAKImplementasiAttachment,
                        $attachment->created_at,
                        $filekey,
                        $filename,
                        true
                    );
                    if ($url) {
                        $attachment->updatePresignedUrl($url);
                    }
                }

                return new SimpleResponse(str_replace('"', '', $url));

            }
            else if (getenv("FILESYSTEM_CLOUD") == FileSystemCloud::LOCAL) {
                $filename = AttachmentHelper::getLocalPath($attachment, $this->attachmentFolder);

                if (!file_exists($filename)) {
                    throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "File Not Found");
                }

                return MediaHelper::fileResponse($filename, $attachment->filename, true);
            }
        }
        else {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "File Not Found or Not active");
        }
    }

    public function deleteAttachment($id)
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $attachmentFile = Attachments::findOrFail([
                "uuid = :uuid:",
                "bind" => [
                    "uuid" => $id
                ]
            ]);
        $attachment_id = $attachmentFile->id;
        $attachment = PAKImplementasiAttachment::findFirst([
                "attachment_id = :attachment_id:",
                "bind" => [
                    "attachment_id" => $attachment_id
                ]
            ]
        );

        if (!empty($Attachment)) {
            $attachment->forceDelete();
        }

        $deleted = \AttachmentHelper::delete($attachmentFile, false);

        if (!$deleted) {
            $this->throwValidationException($attachmentFile->getMessages());
        } else {

            return new CollectionPaginatedResponse([$attachmentFile]);
        }
    }

    public function create()
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $implementasi = new PAKImplementasi();
        $implementasi->created_by = $this->userID;

        $params = $this->validateSaveRequest($this->request, $implementasi);
        $params['status'] = PAKImplementasi::STATUS_DRAFT;

        return $this->save($implementasi, $params);
    }

    public function createAndSubmit()
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $implementasi = new PAKImplementasi();
        $implementasi->created_by = $this->userID;

        $params = $this->validateSaveRequest($this->request, $implementasi);
        $params['status'] = PAKImplementasi::STATUS_SUBMITTED;

        return $this->save($implementasi, $params);
    }

    public function createAndVerify()
    {
        if (!$this->hasRole('admin_pak')) {
            throw new CustomErrorException(BaseResponse::INVALID_AUTHENTICATION_AUTHORIZATION, 'User is not allowed to perform this action');
        }

        $implementasi = new PAKImplementasi();
        $implementasi->created_by = $this->userID;

        $params = $this->validateSaveRequest($this->request, $implementasi);
        $params['status'] = PAKImplementasi::STATUS_VERIFIED;

        $verifications = array_key_exists('verifications', $params) ? $params['verifications'] : null;
        unset($params['verifications']);

        $implementasi->assign($params);
        $saved = $implementasi->save();

        if (!$saved) {
            $this->throwValidationException($implementasi->getMessages());
        }

        $verification_ids = [];
        if ($saved && !is_null($verifications)) {
            foreach ($verifications as $v) {

                $verification = PAKImplementasiVerifikasi::firstOrCreate(
                    [
                        'conditions' => 'implementasi_id = :i_id: AND questionnaire_id = :q_id:',
                        'bind' => [
                            'i_id' => $implementasi->id,
                            'q_id' => $v['questionnaire_id']
                        ]
                    ]
                );

                $verification->implementasi_id = $implementasi->id;
                $verification->questionnaire_id = $v['questionnaire_id'];
                $verification->nilai_verifikasi = 100;
                $verification->verified_by = $this->userID;
                $verification->verified_at = date("Y-m-d H:i:s");
                if ($verification->isNewRecord()) {
                    $verification->created_by = $this->userID;
                } else {
                    $verification->updated_by = $this->userID;
                }

                $saveVerification = $verification->save();
                if(!$saveVerification) {
                    $this->throwValidationException($verification->getMessages());
                }

                array_push($verification_ids, $verification->id);

                $documents = $v['attachment'];
                $doc_ids = [];
                foreach ($documents as $key => $doc) {

                    $attachment = PAKImplementasiAttachment::firstOrCreate("attachment_id = " . $doc['attachment_id']);
                    $attachment->verifikasi_id = $verification->id;
                    $attachment->assign($doc);
                    $attachment->save();

                    array_push($doc_ids, $attachment->attachment_id);
                }

                $verification->syncAttachments($doc_ids);
            }

            $implementasi->syncVerifications($verification_ids);
        }


        return new CollectionPaginatedResponse([$implementasi->getDetail()]);
    }

    public function update($id)
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $implementasi = PAKImplementasi::findOrFail($id);
        $implementasi->updated_by = $this->userID;
        $this->checkImplementasiStatus($implementasi->status);

        $params = $this->validateSaveRequest($this->request, $implementasi);
        $params['status'] = PAKImplementasi::STATUS_DRAFT;

        return $this->save($implementasi, $params);
    }

    public function updateAndSubmit($id)
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $implementasi = PAKImplementasi::findOrFail($id);
        $implementasi->updated_by = $this->userID;
        $this->checkImplementasiStatus($implementasi->status);

        $params = $this->validateSaveRequest($this->request, $implementasi);
        $params['status'] = PAKImplementasi::STATUS_SUBMITTED;

        return $this->save($implementasi, $params);
    }

    protected function checkImplementasiStatus($status)
    {
        if($status == PAKImplementasi::STATUS_SUBMITTED) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                'Implementasi yang sudah disubmit tidak dapat diubah'
            );
        }

        if($status == PAKImplementasi::STATUS_VERIFIED) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                'Implementasi yang sudah diverifikasi tidak dapat diubah'
            );
        }
    }

    protected function checkImplementasiStatusReturned($status)
    {
        if($status == PAKImplementasi::STATUS_DRAFT) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                'Implementasi yang belum disubmit tidak dapat diubah'
            );
        }
    }

    protected function validateSaveRequest($request, $implementasi)
    {
        $params = $request->getJsonRawBody(true);
        $params['instansi_id'] = $request->get('instansi_id', null, $this->shared->user->id_instansi);
        $rules = [
            'instansi_id' => ['validators' => []],
            'verifications' => ['validators' => [
                'required'
            ]],
        ];

        $validatedParams = $this->validate($params, $rules);
        $instansiExist = Instansi::findOrFail($params['instansi_id']);

        if (array_key_exists('verifications', $validatedParams)) {
            $verifications = $validatedParams['verifications'];//dd($verifications);
            $questionnaire_ids = [];
            $attachment_ids = [];
            $attachment_uuids = [];
            foreach ($verifications as $verification) {//dd($verification);

                // validate verification
                if (!array_key_exists('questionnaire_id', $verification)) {
                    throw new ValidationException([
                        'field' => 'questionnaire_id',
                        'message' => 'questionnaire_id tidak boleh kosong'
                    ]);
                }

                if (in_array($verification['questionnaire_id'], $questionnaire_ids)) {
                    throw new ValidationException([
                        'field' => 'questionnaire_id',
                        'message' => 'questionnaire_id tidak boleh sama'
                    ]);
                }

                array_push($questionnaire_ids, $verification['questionnaire_id']);

                if (array_key_exists('attachment', $verification)) {

                    if (!is_array($verification['attachment'])) {
                        throw new ValidationException([
                            'field' => 'attachment',
                            'message' => 'format attachment salah'
                        ]);
                    }

                    //dd($verification['attachment']);
                    foreach ($verification['attachment'] as $attachment) {

                        //dd($attachment);
                        $valid = $this->validateAttachment($attachment, $implementasi);

                        if (array_key_exists('attachment_id', $attachment)) {
                            if(in_array($attachment['attachment_id'], $attachment_ids)) {
                                throw new ValidationException([
                                    'field' => 'attachment_id',
                                    'message' => 'attachment_id tidak boleh sama'
                                ]);
                            }
                            $attachment_ids[] = $attachment['attachment_id'];
                        } else if (array_key_exists('uuid', $attachment)) {
                            if(in_array($attachment['uuid'], $attachment_uuids)) {
                                throw new ValidationException([
                                    'field' => 'uuid',
                                    'message' => 'uuid tidak boleh sama'
                                ]);
                            }
                            $attachment_uuids[] = $attachment['uuid'];
                        }
                    }
                }
            }
        }

        return $validatedParams;
    }

    protected function validateAttachment($attachment, $implementasi)
    {
        $current_year = (int) date("Y");

        $rules = [
            'attachment_id' => ['validators' => ['digit']],
            'uuid' => ['validators' => []],
            'filename' => ['validators' => []],
            'jenis_dokumen_id' => ['validators' => ['digit']],
            'nomor' => ['validators' => []],
            'tentang' => ['validators' => []],
            'tanggal_ttd' => ['validators' => []],
        ];

        if (array_key_exists('tahun', $attachment)) {
            $rules['tahun'] = ['validators' => [
                'digit',
                [
                    'name' => 'min',
                    'params' => 2017,
                ],
                [
                    'name' => 'max',
                    'params' => $current_year,
                ],
            ]];
        }

        $params = $this->filterExpectedRequest($attachment, $rules);
        if (empty($params['attachment_id']) && ( empty($params['uuid']) || empty($params['filename']) ))
        {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Attachment ID atau UUID tidak boleh kosong!");
        }

        if (!empty($params['attachment_id'])) {
            $attachment = Attachments::findOrFail($params['attachment_id']);
            if ($implementasi->isNewRecord() && $attachmentExist = PAKImplementasiAttachment::findFirst("attachment_id = " . $params['attachment_id'])) {
                throw new ValidationException([
                    'field' => 'attachment_id',
                    'message' => 'ID ' .$params['attachment_id']. ' sudah digunakan'
                ]);
            }
        } elseif (!empty($params['uuid'])) {
            if ($implementasi->isNewRecord() && $attachmentExist = Attachments::findFirst("uuid = '" . $params['uuid'] . "'")) {
                throw new ValidationException([
                    'field' => 'attachment_id',
                    'message' => 'UUID ' .$params['uuid']. ' sudah digunakan'
                ]);
            }
        }

        if (array_key_exists('jenis_dokumen_id', $params) && !is_null($params['jenis_dokumen_id'])) {

            $dokumen = PAKJenisDokumenQuestionnaire::findOrFail($params['jenis_dokumen_id']);
        }

        return $params;
    }

    protected function save($implementasi, $params)
    {
        $verifications = array_key_exists('verifications', $params) ? $params['verifications'] : null;
        unset($params['verifications']);

        $implementasi->assign($params);
        $saved = $implementasi->save();//$saved = false;

        if (!$saved) {
            $this->throwValidationException($implementasi->getMessages());
        }

        $verification_ids = [];
        if ($saved && !is_null($verifications)) {
            foreach ($verifications as $v) {

                $verification = PAKImplementasiVerifikasi::firstOrCreate(
                    //"implementasi_id = ".$v['questionnaire_id']
                    [
                        'conditions' => 'implementasi_id = :i_id: AND questionnaire_id = :q_id:',
                        'bind' => [
                            'i_id' => $implementasi->id,
                            'q_id' => $v['questionnaire_id']
                        ]
                    ]
                );

                $verification->implementasi_id = $implementasi->id;
                $verification->questionnaire_id = $v['questionnaire_id'];
                $verification->nilai_verifikasi = 0;
                if ($verification->isNewRecord()) {
                    $verification->created_by = $this->userID;
                } else {
                    $verification->updated_by = $this->userID;
                }

                $saveVerification = $verification->save();
                if(!$saveVerification) {
                    $this->throwValidationException($verification->getMessages());
                }

                $verification_ids[] = $verification->id;

                $documents = $v['attachment'];
                $doc_ids = [];
                foreach ($documents as $key => $doc) {
                    if (array_key_exists('uuid', $doc) && !empty($doc['uuid']) && array_key_exists('filename', $doc) && !empty($doc['filename'])) {
                        $attachment = new Attachments();
                        $attachment->uuid = $doc['uuid'];
                        $attachment->filename = $doc['filename'];
                        $attachment->tipe = Attachments::TIPE_PUBLIC;
                        $attachment->status = Attachments::STATUS_CREATED;
                        $attachment->created_by = $this->shared->user->um_id;
                        if (!$attachment->save()) {
                            $this->throwValidationException($attachment->getMessages());
                        }

                        $doc['attachment_id'] = $attachment->id;
                    }
                    $attachment = PAKImplementasiAttachment::firstOrCreate("attachment_id = " . $doc['attachment_id']);
                    $attachment->verifikasi_id = $verification->id;
                    $attachment->assign($doc);
                    $attachment->save();

                    $doc_ids[] = $attachment->attachment_id;
                }

                $verification->syncAttachments($doc_ids);
            }

            $implementasi->syncVerifications($verification_ids);
        }


        return new CollectionPaginatedResponse([$implementasi->getDetail()]);
    }

    public function returned()
    {
        $this->checkScopes(['pak.verify.implementasi']);

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validate(
            $rawBody,
            [
                'verifikasi_id' => ['validators' => ['digit', 'required']],
                'returned_notes' => ['validators' => []]
            ]
        );
        $model = PAKImplementasiVerifikasi::findOrFail($params['verifikasi_id']);

        /** @var PAKImplementasi $implementasi */
        $implementasi = PAKImplementasi::findOrFail($model->implementasi_id);
        $this->checkImplementasiStatusReturned($implementasi->status);
        $implementasi->status = PAKImplementasi::STATUS_DRAFT;
        $implementasi->returned_at = 'now()';
        $implementasi->returned_by = $this->userID;
        if (!empty($rawBody['returned_notes'])) $implementasi->returned_notes = $params['returned_notes'];
        if (!$implementasi->save()) {
            $this->throwValidationException($implementasi->getMessages());
        } else {
            // todo uncomment di branch issue #1124
            // $this->mailToStakeholder($implementasi);
        }

        return new CollectionPaginatedResponse([$implementasi->toArray()]);
    }

    public function verify()
    {
        $this->checkScopes(['pak.verify.implementasi']);

        $rawBody = $this->request->getJsonRawBody(true);

        $params = $this->validateVerification($rawBody, true);
        $model = PAKImplementasiVerifikasi::findOrFail($params['verifikasi_id']);
        $model->assign($params);
        $model->verified_by = $this->userID;
        $model->verified_at = date("Y-m-d H:i:s");

        $saved = $model->save();

        if (!$saved) {

            $this->throwValidationException($model->getMessages());
        } else {
            $implementasi = PAKImplementasi::findOrFail($model->implementasi_id);
            $implementasi->status = PAKImplementasi::STATUS_VERIFIED;
            $implementasi->save();

            return new CollectionPaginatedResponse([$model->toArray()]);
        }
    }

    public function batchVerify()
    {
        $this->checkScopes(['pak.verify.implementasi']);

        $rawBody = $this->request->getJsonRawBody(true);

        if(!isset($rawBody['verifications'])) {
            throw new CustomErrorException(
                BaseResponse::INVALID_REQUEST,
                'Input Json tidak sesuai'
            );
        }
        $verifications = $rawBody['verifications'];
        $models = [];
        $params = [];

        foreach ($verifications as $key => $value) {
            $params[$key] = $this->validateVerification($value, true);
            $models[$key] = PAKImplementasiVerifikasi::findOrFail($value['verifikasi_id']);

            $params[$key]['verified_by'] = $this->userID;
            $params[$key]['verified_at'] = date("Y-m-d H:i:s");
        }

        $results = [];
        $implementasi_id = 0;
        foreach ($models as $key => $model) {
            $model->assign($params[$key]);
            $model->save();

            $results[] = $model->toArray();
            $implementasi_id = $model->implementasi_id;
        }

        $implementasi = PAKImplementasi::findOrFail($implementasi_id);
        $implementasi->status = PAKImplementasi::STATUS_VERIFIED;
        $implementasi->save();

        return new CollectionPaginatedResponse([$results]);
    }

    public function delete($id)
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $rawBody = $this->request->getJsonRawBody(true);
        $this->validateDeleteAndRestoreRequest($rawBody, $id);

        $model = PAKImplementasi::findOrFail($id);

        if($model->status == PAKImplementasi::STATUS_SUBMITTED) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                'Implementasi yang sudah disubmit tidak dapat dihapus'
            );
        }

        if($model->status == PAKImplementasi::STATUS_VERIFIED) {
            throw new \CustomErrorException(
                \BaseResponse::INVALID_REQUEST,
                'Implementasi yang sudah diverifikasi tidak dapat dihapus'
            );
        }

        $deleted = $model->delete($this->userID);

        if (!$deleted) {
            $this->throwValidationException($model->getMessages());
        } else {

            return new CollectionPaginatedResponse([$model]);
        }
    }

    public function destroy($id)
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $rawBody = $this->request->getJsonRawBody(true);
        $this->validateDeleteAndRestoreRequest($rawBody, $id);

        $model = PAKImplementasi::findOrFail($id);

        $verifications = $model->verifications;
        if(!empty($verifications)) {
            foreach ($verifications as $key => $ver) {
                $attachments = $ver->attachments;
                if(!empty($attachments)) {
                    foreach ($attachments as $key => $att) {
                        $a = $att->attachment;
                        if(!empty($a)) $a->delete();
                        $att->forceDelete();
                    }
                }
                $ver->forceDelete();
            }
        }

        $deleted = $model->forceDelete();

        if (!$deleted) {
            $this->throwValidationException($model->getMessages());
        } else {

            return new CollectionPaginatedResponse([$model]);
        }
    }

    public function restore($id)
    {
        $this->checkScopes(['pak.manage.implementasi']);

        $rawBody = $this->request->getJsonRawBody(true);
        $this->validateDeleteAndRestoreRequest($rawBody, $id);

        $model = PAKImplementasi::findOrFail($id, true);

        $restored = $model->restore($this->userID);

        if (!$restored) {
            $this->throwValidationException($model->getMessages());
        } else {

            return new CollectionPaginatedResponse([$model]);
        }
    }

    public function listInstansi() {
        $this->hasRole('admin_pak');

        $getParams = $this->request->get();

        $getParams['limit'] = $this->getDefaultLimit($getParams);
        $getParams['offset'] = array_key_exists('offset', $getParams) ? $getParams['offset'] : 0;
        $getParams['keyword'] = array_key_exists('keyword', $getParams) ? $getParams['keyword'] : '';

        $params = $this->validate(
            $getParams,
            [
                'limit' => ['validators' => ['digit']],
                'offset' => ['validators' => ['digit']],
                'keyword' => ['validators' => []]
            ]
        );

        $conditions = [
            'conditions' => 'nama ilike :keyword: AND flag_pak = true',
            'bind' => [
                'keyword' => '%' . $params['keyword'] . '%'
            ]
        ];

        $instansiList = Instansi::find(array_merge($conditions, [
            'limit' => $params['limit'], 'offset' => $params['offset']
        ]));

        $total_instansi = Instansi::find($conditions)->count();

        return new PaginatedResponse($instansiList, $total_instansi, $params['limit'], $params['offset']);
    }

    protected function validateVerification($request, $toVerify = false)
    {
        if ($toVerify) {
            $rules['nilai_verifikasi'] = ['validators' => [
                'required',
                'digit',
                [
                    'name' => 'between',
                    'params' => [
                        'min' => 0,
                        'max' => 100,
                    ],
                ],
            ]];
            $rules['verifikasi_id'] = ['validators' => ['required', 'digit']];
            $params = $this->filterExpectedRequest($request, $rules);
        }
        else {
            $rules['questionnaire_id'] = ['validators' => ['required', 'digit']];
            $params = $this->filterExpectedRequest($request, $rules);
            $checkQuestion = PAKQuestionnaire::findOrFail($params['questionnaire_id']);
        }

        return $params;
    }

    /**
     * @params $request post request
     * @params $id get request id
     */
    protected function validateDeleteAndRestoreRequest($request, $id)
    {
        $params = $this->filterExpectedRequest(
            $request,
            [
                'id' => ['validators' => ['required', 'digit']],
            ]
        );

        if ($params['id'] != $id) {
            throw new CustomErrorException(
                BaseResponse::INVALID_REQUEST,
                'ID tidak sesuai'
            );
        }

        return $params;
    }

    private function mailToStakeholder(PAKImplementasi $PAKImplementasi) {
        switch ($PAKImplementasi->status) {
            case PAKImplementasi::STATUS_DRAFT:
                $this->mailReturnedToStakeholder($PAKImplementasi);
                break;
            default:
                break;
        }
    }

    private function mailReturnedToStakeholder(PAKImplementasi $PAKImplementasi) {
        $stakeholders = UmUser::findUserByScopeAndInstansi('pak.manage.implementasi', $PAKImplementasi->instansi_id);
        $mailHelper = new MailHelper($this->config['mail_config']);
        foreach ($stakeholders as $stakeholder) {
            $mailHelper->queue(
                $stakeholder['email'],
                "[JAGA] Laporan Implementasi PAK Dikembalikan ke Draf",
                "$PAKImplementasi->returned_notes",
                true
            );
        }
    }

}
