<?php

class PancekKomponenIndikatorController extends BaseController
{
    public function list()
    {
        $getParams = $this->request->get();

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

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

        $conditions = "PancekKomponenIndikator.label ilike :keyword: AND PancekKomponenIndikator.deleted_at IS NULL";
        $countConditions = "ki.label ilike :keyword AND ki.deleted_at IS NULL";
        $bind = [
            'keyword' => '%' . $params['keyword'] . '%'
        ];

        if (!is_null($params['konsep_sistem_pencegahan_id'])) {
            $conditions .= " AND PancekIndikator.konsep_sistem_pencegahan_id = :konsep_sistem_pencegahan_id:";
            $countConditions .= " AND i.konsep_sistem_pencegahan_id = :konsep_sistem_pencegahan_id";
            $bind['konsep_sistem_pencegahan_id'] = $params['konsep_sistem_pencegahan_id'];
        }

        if (!is_null($params['indikator_id'])) {
            $conditions .= " AND PancekIndikator.id = :indikator_id:";
            $countConditions .= " AND i.id = :indikator_id";
            $bind['indikator_id'] = $params['indikator_id'];
        }

        $records = PancekKomponenIndikator::query()
        ->columns("
            PancekKomponenIndikator.id, PancekKomponenIndikator.indikator_id, PancekKomponenIndikator.code, PancekKomponenIndikator.parent_code, PancekKomponenIndikator.label, PancekKomponenIndikator.label_en, PancekKomponenIndikator.is_header, PancekKomponenIndikator.view_order, PancekKomponenIndikator.bobot, PancekKomponenIndikator.formulir_type, 
            PancekIndikator.code as indikator_code
        ")
        ->leftJoin("PancekIndikator", "PancekIndikator.id = PancekKomponenIndikator.indikator_id")
        ->where($conditions)
        ->bind($bind)
        ->orderBy("PancekKomponenIndikator.indikator_id, PancekKomponenIndikator.view_order")
        ->limit($params['limit'], $params['offset'])
        ->execute()
        ->toArray();

        $rows = [];

        if ($params['with_templates']) {
            foreach ($records as $record) {
                $komponenIndikator = new PancekKomponenIndikator();
                $komponenIndikator->id = $record['id'];
                $row = $record;
                $templates = [];
                foreach ($komponenIndikator->templates as $template) {
                    array_push($templates, $template->getDetail(['id', 'label', 'language']));
                }
                $row['templates'] = $templates;
                array_push($rows, $row);
            }
        } else {
            $rows = $records;
        }

        $total = $this->rawQuery("SELECT COUNT(*) as total FROM jaga.pancek_komponen_indikator ki LEFT JOIN jaga.pancek_indikator i ON i.id = ki.indikator_id WHERE $countConditions", $bind)[0]['total'];

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

    public function form()
    {
        $params = $this->validate(
            $this->request->get(),
            [
                'formulir_type' => ['validators' => ['required', 'digit']]
            ]);
        $records = (new PancekKonsepSistemPencegahan)->getForm(
            [
                'conditions' => 'deleted_at IS NULL AND formulir_type = :type:',
                'bind' => ['type' => $params['formulir_type']]
            ]
        );

        return new SimpleResponse($records);
    }

    public function detail($id)
    {
        /** @var $record PancekKomponenIndikator */
        $record = PancekKomponenIndikator::findFirst($id);
        if (!$record) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Komponen [#' . $id . '] tidak ditemukan');
        }

        return new SimpleResponse($record->toDetail());
    }

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

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validate(
            $rawBody,
            [
                "indikator_id" => ['validators' => ['required', 'digit']],
                "code" => ['validators' => ['required', [
                    'name' => 'max_string',
                    'params' => 30
                ]]],
                "parent_code" => ['validators' => [[
                    'name' => 'max_string',
                    'params' => 30
                ]]],
                "label" => ['validators' => ['required']],
                "label_en" => ['validators' => ['required']],
                "is_header" => ['validators' => ['required']],
                "view_order" => ['validators' => ['required', 'digit']],
                "bobot" => ['validators' => [
                    'numeric',
                    [
                        'name' => 'min',
                        'params' => 0
                    ],
                    [
                        'name' => 'max',
                        'params' => 100
                    ],
                ]],
                "templates" => ['validators' => []],
                "formulir_type" => ['validators' => ['required', [
                    'name' => 'inclusion_in',
                    'params' => PancekJenisInstansi::TIPE_FORMULIR
                ]]]
            ]
        );

        /** @var $record PancekKomponenIndikator */
        $record = PancekKomponenIndikator::findFirst($id);
        if (!$record) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Komponen [#' . $id . '] tidak ditemukan');
        }

        $indikator = PancekKomponenIndikator::findFirst($params['indikator_id']);
        if (!$indikator) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Indikator [#' . $params['indikator_id'] . '] tidak ditemukan');
        }

        if (!is_null($params['parent_code'])) {
            $komponen = PancekKomponenIndikator::findFirst(['conditions' => 'code = :code: AND formulir_type = :formulir_type:', 'bind' => ['code' => $params['parent_code'], 'formulir_type' => $params['formulir_type']]]);
            if (!$komponen) {
                throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Komponen dengan code ['.$params['parent_code'].'] tidak ditemukan');
            }
        }

        $attachment_ids = [];
        if (!empty($params['templates'])) {
            foreach ($params['templates'] as $attachment) {
                $this->validate(
                    $attachment,
                    [
                        "attachment_id" => ['validators' => ['required', 'digit']],
                        "label" => ['validators' => []],
                        "language" => ['validators' => [
                            [
                                'name' => 'inclusion_in',
                                'params' => ['ID', 'EN']
                            ]
                        ]]
                    ]
                );
                $attachmentRecord = Attachments::findFirst($attachment['attachment_id']);
                if ($attachmentRecord && empty($attachmentRecord->deleted_at)) {
                    $attachmentRecord->status = Attachments::STATUS_REFERRED;
                    $attachmentRecord->referer = Attachments::REFERER_PANCEK_KOMPONEN_TEMPLATE;
                    $attachmentRecord->save();

                    $komponenTemplate = PancekKomponenTemplate::firstOrCreate("attachment_id = " . $attachmentRecord->id);
                    $komponenTemplate->komponen_indikator_id = $id;
                    $komponenTemplate->attachment_id = $attachmentRecord->id;
                    $komponenTemplate->label = $attachment['label'];
                    $komponenTemplate->language = $attachment['language'];
                    if ($komponenTemplate->isNewRecord()) {
                        $komponenTemplate->created_at = DateHelper::getNowTimezoned();
                    } else {
                        $komponenTemplate->updated_at = DateHelper::getNowTimezoned();
                    }
                    $komponenTemplate->save();
                    array_push($attachment_ids, $komponenTemplate->attachment_id);
                } else {
                    throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Attachment [#" . $attachment['attachment_id'] . "] tidak ditemukan");
                }
            }
        }

        $record->assign($params);
        $record->updated_at = DateHelper::getNowTimezoned();

        $status = $record->save();

        if (!$status) {
            $errors = $record->getMessages();
            $error_messages = [];

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

            throw new ValidationException($error_messages);
        } else {
            $record->syncAttachments($attachment_ids);
            return new SimpleResponse($record->toDetail());
        }
    }

    public function massUpdate()
    {
        $this->hasOneOfScopes(['pancek.admin']);

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

        $result = [
            'success' => 0,
            'failed' => 0,
            'failed_messages' => []
        ];
        foreach ($payload['payload'] as $p)
        {
            $this->validate($p, [
                'id' => ['validators' => ['required', 'digit']],
                "code" => ['validators' => ['required', [
                    'name' => 'max_string',
                    'params' => 30
                ]]],
                "parent_code" => ['validators' => [[
                    'name' => 'max_string',
                    'params' => 30
                ]]],
                "label" => ['validators' => ['required']],
                "is_header" => ['validators' => ['required']],
                "view_order" => ['validators' => ['required', 'digit']],
                "bobot" => ['validators' => [
                    'numeric',
                    [
                        'name' => 'min',
                        'params' => 0
                    ],
                    [
                        'name' => 'max',
                        'params' => 100
                    ],
                ]]
            ]);

            if (!is_bool($p['is_header'])) {
                throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Param `is_header` harus berupa boolean");
            }

            $komponenIndikator = PancekKomponenIndikator::findFirst($p['id']);
            if (!$komponenIndikator) {
                $result['failed']++;
                array_push($result['failed_messages'], "Komponen Indikator #".$p['id']." tidak ditemukan");
            } else {
                unset($p['id']);
                $komponenIndikator->assign($p);
                if ($komponenIndikator->save()) {
                    $result['success']++;
                } else {
                    $result['failed']++;
                    $errors = $komponenIndikator->getMessages();
                    $error_messages = [];

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

        return new SimpleResponse($result);
    }
}
