<?php

class LitbangKajianRepositoriController extends BaseController {
    public function index() {
        $this->checkScopes(['litbang.access']);
        $params = $this->request->get();
        $params['sektor_id'] = array_key_exists('sektor_id', $params) ? $params['sektor_id'] : -1;
        $params['judul'] = array_key_exists('judul', $params) ? $params['judul'] : "";
        $params['status'] = array_key_exists('status', $params) ? $params['status'] : "%%";
        $params['keyword'] = array_key_exists('keyword', $params) ? $params['keyword'] : "%%";
        $params['tahun'] = array_key_exists('tahun', $params) ? $params['tahun'] : -1;
        $params['limit'] = $this->getDefaultLimit($params);
        $params['offset'] = array_key_exists('offset', $params) ? $params['offset'] : 0;
        $params['order_by'] = array_key_exists('order_by', $params) ? strtolower($params['order_by']) : 'id';
        $params['order_direction'] = array_key_exists('order_direction', $params) ? strtolower($params['order_direction']) : 'asc';

        $allowed_order = [
            'id',
            'sektor_id',
            'judul',
            'status',
            'tahun',
            'created_at',
            'updated_at'
        ];
        $allowed_order_direction = ['asc', 'desc'];

        $this->validate(
            $params,
            [
                'sektor_id' => ['validators' => ['digit']],
                'judul' => ['validators' => []],
                'status' => ['validators' => []],
                'tahun' => ['validators' => ['digit']],
                'keyword' => ['validators' => []],
                'limit' => ['validators' => ['digit']],
                'offset' => ['validators' => ['digit']],
                'order_by' => ['validators' =>  [[
                    'name' => 'inclusion_in',
                    'params' => $allowed_order
                ]]],
                'order_direction' => ['validators' =>  [[
                    'name' => 'inclusion_in',
                    'params' => $allowed_order_direction
                ]]]
            ]
        );

        $conditions = [
            'conditions' => "
                (sektor_id = :sektor_id: OR 0 > :sektor_id:) AND 
                judul ILIKE :judul: AND 
                status LIKE :status: AND 
                (tahun = :tahun: OR 0 > :tahun:) AND 
                (judul ILIKE :keyword: OR daftar_peneliti ILIKE :keyword: OR kata_kunci ILIKE :keyword:)
            ",
            'bind' => [
                'sektor_id' => $params['sektor_id'],
                'judul' => "%" . $params['judul'] . "%",
                'status' => $params['status'],
                'tahun' => $params['tahun'],
                'keyword' => "%" . $params['keyword'] . "%",
            ],
            'order' =>  $params['order_by'] . " " . $params['order_direction'],
        ];

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

        $result = [];
        foreach ($data as $row) {
            /** @var $row LitbangKajianRepositori  */
            array_push($result, $row->getDetail());
        }

        $total = LitbangKajianRepositori::find($conditions)->count();

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

    public function create() {
        $this->checkOneOfScopes(['litbang.admin', 'litbang.submit']);
        $params = $this->validateSave($this->request->getJsonRawBody(true), null);

        $this->db->begin();
        try{
            $record = new LitbangKajianRepositori();
            $record->assign($params);
            $record->src = LitbangKajianRepositori::SRC_REPOSITORI;
            $record->kode = $record->generateCode();

            $status = $record->save();
            if (!$status) {
                $this->throwValidationError($record);
            } else {
                if (!empty($params['attachments'])) {
                    foreach ($params['attachments'] as $attachment) {
                        $attachment_record = Attachments::findFirst($attachment['attachment_id']);
                        if (!empty($attachment_record) && empty($attachment_record->deleted_at)) {
                            $attachment_record->status = Attachments::STATUS_REFERRED;
                            $attachment_record->referer = Attachments::REFERER_LITBANG_KAJIAN_PENGAJUAN;
                            if (!$attachment_record->save()) {
                                $this->throwValidationError($attachment_record);
                            }

                            $attachment_kajian = LitbangKajianRepositoriAttachment::firstOrCreate("attachment_id = " . $attachment_record->id);
                            $attachment_kajian->attachment_id = $attachment_record->id;
                            $attachment_kajian->kajian_repositori_id = $record->id;
                            $attachment_kajian->jenis_dokumen_id = $attachment['jenis_dokumen_id'];
                            $attachment_kajian->created_by = $this->userID;
                            $attachment_kajian->updated_by = $this->userID;
                            if (!$attachment_kajian->save()) {
                                $this->throwValidationError($attachment_kajian);
                            }
                        }
                    }
                }

                $this->syncKlpds($params, $record);

                if ($record->status == LitbangKajianRepositori::STATUS_PUBLISHED) {
                    LitbangService::createKajianFromRepositori($record);
                }

                $this->db->commit();
                return new CollectionPaginatedResponse([$record]);
            }
        } catch (\Exception $e) {
            $this->db->rollback();
            throw $e;
        }
    }

    public function update($id) {
        $this->checkOneOfScopes(['litbang.admin', 'litbang.submit']);

        /** @var $record LitbangKajianRepositori */
        $record = LitbangKajianRepositori::findFirst($id);

        if (empty($record)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Kajian tidak ditemukan');
        }

        $params = $this->validateSave($this->request->getJsonRawBody(true), $id);

        $this->db->begin();
        try {
            $attachment_ids = [];
            if (!empty($params['attachments'])) {
                foreach ($params['attachments'] as $attachment) {
                    $attachment_record = Attachments::findFirst($attachment['attachment_id']);
                    if (!empty($attachment_record) && empty($attachment_record->deleted_at)) {
                        $attachment_record->status = Attachments::STATUS_REFERRED;
                        $attachment_record->referer = Attachments::REFERER_LITBANG_KAJIAN_PENGAJUAN;
                        if (!$attachment_record->save()) {
                            $this->throwValidationError($attachment_record);
                        }

                        /** @var $attachment_repositori LitbangKajianRepositoriAttachment */
                        $attachment_repositori = LitbangKajianRepositoriAttachment::firstOrCreate("attachment_id = " . $attachment_record->id);
                        $attachment_repositori->kajian_repositori_id = $record->id;
                        $attachment_repositori->attachment_id = $attachment_record->id;
                        $attachment_repositori->jenis_dokumen_id = $attachment['jenis_dokumen_id'];
                        if ($attachment_repositori->isNewRecord()) {
                            $attachment_repositori->created_by = $this->userID;
                        } else {
                            $attachment_repositori->updated_at = date('Y-m-d H:i:s');
                            $attachment_repositori->updated_by = $this->userID;
                        }
                        if (!$attachment_repositori->save()) {
                            $this->throwValidationError($attachment_repositori);
                        }
                        array_push($attachment_ids, $attachment_repositori->attachment_id);
                    }
                }
            }

            $record->assign($params);
            $record->updated_at = date('Y-m-d H:i:s');
            $status = $record->save();

            if (!$status) {
                $this->throwValidationError($record);
            } else {
                $record->syncAttachments($attachment_ids, "PUB");
                $this->syncKlpds($params, $record);

                if ($record->status == LitbangKajianRepositori::STATUS_PUBLISHED) {
                    LitbangService::createKajianFromRepositori($record);
                }

                $this->db->commit();
                return new CollectionPaginatedResponse([$record]);
            }
        }
        catch (\Exception $e) {
            $this->db->rollback();
            throw $e;
        }
    }

    public function uploadDocument()
    {
        $this->checkOneOfScopes(['litbang.admin', 'litbang.submit']);
        $postParams = $this->request->getPost();

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

        $result = LitbangService::uploadDocument(
            $this->shared,
            $this->minio,
            $this->request,
            LitbangKajianRepositoriAttachment::DOCUMENT_DIR,
            $this->config["allowed_mime_types"],
            5
        );

        return new CollectionPaginatedResponse($result);
    }

    public function downloadDocument($uuid)
    {
        $this->checkScopes(['litbang.access']);
        return LitbangService::downloadAttachment(
            $this->shared,
            $this->minio,
            LitbangKajianRepositoriAttachment::DOCUMENT_DIR,
            $uuid
        );
    }

    public function detail($id)
    {
        $this->checkScopes(['litbang.access']);
        /** @var $result LitbangKajianRepositori */
        $result = LitbangKajianRepositori::findFirst([
            'conditions' => 'id = :id: AND deleted_at is null',
            'bind' => [
                'id' => $id
            ]
        ]);

        if (empty($result)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Kajian tidak ditemukan');
        }

        return new SimpleResponse($result->getDetail());
    }

    public function jenisDokumen()
    {
        $this->checkScopes(['litbang.access']);
        $result = LitbangKajianPengajuanJenisDokumen::findByTahapan('PUB');
        return new CollectionPaginatedResponse($result);
    }

    private function validateSave($request, $id) {
        if ($id) {
            $data = LitbangKajianRepositori::findFirst($id);
            if (!$data) {
                throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Kajian dengan ID [' . $id . '] tidak ditemukan');
            }
            if ($data->status == LitbangKajianRepositori::STATUS_PUBLISHED) {
                throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Kajian yang sudah dirilis tidak dapat diubah");
            }
        }

        $validations = [
            "sektor_id" => ['validators' => ['required', 'digit']],
            "pengajuan_id" => ['validators' => ['digit']],
            "tahun" => ['validators' => ['required', 'digit']],
            "judul" => ['validators' => ['required']],
            "latar_belakang" => ['validators' => []],
            "tujuan_penelitian" => ['validators' => []],
            "metode_pengumpulan_data" => ['validators' => []],
            "lokasi_subyek" => ['validators' => []],
            "abstrak" => ['validators' => []],
            "kata_kunci" => ['validators' => []],
            "kesimpulan" => ['validators' => []],
            "daftar_peneliti" => ['validators' => []],
            "kontak_peneliti" => ['validators' => []],
            "mitra_kerjasama" => ['validators' => []],
            "narasumber" => ['validators' => []],
            "submit_status" => ['validators' => []],
            "attachments" => ['validator' => []],
            "klpds" => ['validator' => []],
        ];
        if (!empty($request['tgl_presentasi'])) {
            $validations = array_merge($validations, [
                "tgl_presentasi" => ['validators' => ['date']]
            ]);
        }
        if (!empty($request['tgl_publikasi'])) {
            $validations = array_merge($validations, [
                "tgl_publikasi" => ['validators' => ['date']]
            ]);
        }
        $params = $this->validate(
            $request,
            $validations
        );
        $this->validateJenisDokumen("PUB", $params['attachments']);

        $sektor = LitbangKajianSektor::findFirst([
            'conditions' => 'id = :sektor_id: AND deleted_at is null',
            'bind' => [
                'sektor_id' => $params['sektor_id']
            ]
        ]);

        if (empty($sektor)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Sektor tidak ditemukan');
        }

        $params['status'] = $params['submit_status'] == LitbangKajianRepositori::STATUS_PUBLISHED ? LitbangKajianRepositori::STATUS_PUBLISHED : LitbangKajianRepositori::STATUS_DRAFT;

        return $params;
    }

    private function validateJenisDokumen($tahapan, $attachments) {
        $jenisDokumens = LitbangKajianPengajuanJenisDokumen::findByTahapan($tahapan)->toArray();
        $jenisDokumenIds = array_column($jenisDokumens, 'id');
        if ($attachments) {
            foreach ($attachments as $attachment) {
                $this->validate(
                    $attachment,
                    [
                        "attachment_id" => ['validators' => ['required', 'digit']],
                        "jenis_dokumen_id" => ['validators' => ['required', 'digit']],
                    ]
                );
                if (!in_array($attachment['jenis_dokumen_id'], $jenisDokumenIds)) {
                    throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Jenis dokumen tidak valid!");
                }
            }
        }
    }

    private function validateJson($string, $key) {
        json_encode($string);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Format " . $key . " tidak valid!");
        }
    }

    private function throwValidationError($model) {
        $errors = $model->getMessages();
        $error_messages = [];

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

        throw new ValidationException($error_messages);
    }

    public function syncKlpds($params, LitbangKajianRepositori $litbangKajianRepository)
    {
        $klpd_ids = [];
        $rekomendasi_ids = [];
        foreach ($params['klpds'] as $klpd) {

            /** @var $litbangKajianKlpd LitbangKajianKlpd */
            $litbangKajianKlpd = false;
            if (!empty($klpd['id'])) {
                $litbangKajianKlpd = LitbangKajianKlpd::findFirst("id = " . $klpd['id']);
            }
            if (!$litbangKajianKlpd) {
                $litbangKajianKlpd = new LitbangKajianKlpd();
            }
            $litbangKajianKlpd->kajian_id = $litbangKajianRepository->id;
            $litbangKajianKlpd->instansi_id = $klpd['instansi']['id'];
            $litbangKajianKlpd->src = LitbangKajianKlpd::SRC_REPOSITORI;
            if (!$litbangKajianKlpd->isNewRecord()) {
                $litbangKajianKlpd->updated_at = date('Y-m-d');
            }
            if (!$litbangKajianKlpd->save()) {
                $this->throwValidationError($litbangKajianKlpd);
            }

            if (!empty($klpd['rekomendasi_list'])) {
                foreach ($klpd['rekomendasi_list'] as $rekomendasi) {

                    /** @var $litbangKajianKlpdRekomendasi LitbangKajianKlpdRekomendasi */
                    $litbangKajianKlpdRekomendasi = false;
                    if (!empty($rekomendasi['id'])) {
                        $litbangKajianKlpdRekomendasi = LitbangKajianKlpdRekomendasi::findFirst("id = " . $rekomendasi['id']);
                    }
                    if (!$litbangKajianKlpdRekomendasi) {
                        $litbangKajianKlpdRekomendasi = new LitbangKajianKlpdRekomendasi();
                    }
                    $litbangKajianKlpdRekomendasi->kajian_klpd_id = $litbangKajianKlpd->id;
                    $litbangKajianKlpdRekomendasi->konten = $rekomendasi['konten'];
                    if (!$litbangKajianKlpdRekomendasi->isNewRecord()) {
                        $litbangKajianKlpdRekomendasi->updated_at = date('Y-m-d');
                    }
                    if (!$litbangKajianKlpdRekomendasi->save()) {
                        $this->throwValidationError($litbangKajianKlpdRekomendasi);
                    }
                    array_push($rekomendasi_ids, $litbangKajianKlpdRekomendasi->id);

                }
            }
            array_push($klpd_ids, $litbangKajianKlpd->id);

        }

        $klpds = LitbangKajianKlpd::find([
            'conditions' => 'kajian_id = :id: AND src = :src:',
            'bind' => ['id' => $litbangKajianRepository->id, 'src' => LitbangKajianKlpd::SRC_REPOSITORI]
        ]);

        if ($klpds->count() > 0) {
            foreach ($klpds as $klpd) {
                if (!in_array($klpd->id, $klpd_ids)) {
                    $rekomendasis = LitbangKajianKlpdRekomendasi::find([
                        'conditions' => 'kajian_klpd_id = :id:',
                        'bind' => ['id' => $klpd->id]
                    ]);
                    foreach ($rekomendasis as $rekomendasi) {
                        $rekomendasi->deleted_at = date('Y-m-d H:i:s');
                        $rekomendasi->updated_at = date('Y-m-d H:i:s');
                        $rekomendasi->save();
                    }
                    $klpd->deleted_at = date('Y-m-d H:i:s');
                    $klpd->updated_at = date('Y-m-d H:i:s');
                    $klpd->save();
                } else {
                    $rekomendasis = LitbangKajianKlpdRekomendasi::find([
                        'conditions' => 'kajian_klpd_id = :id:',
                        'bind' => ['id' => $klpd->id]
                    ]);
                    foreach ($rekomendasis as $rekomendasi) {
                        if (!in_array($rekomendasi->id, $rekomendasi_ids)) {
                            $rekomendasi->deleted_at = date('Y-m-d H:i:s');
                            $rekomendasi->updated_at = date('Y-m-d H:i:s');
                            $rekomendasi->save();
                        }
                    }
                }
            }
        }
    }
}
