<?php

//namespace Jaga\Controllers;

use Jaga\Models\PAK\PAKQuestionnaire;
use Jaga\Models\PAK\PAKJenisDokumenQuestionnaire;

class PAKQuestionnaireController extends BaseController
{
    public function onConstruct()
    {
        parent::onConstruct();
        $this->checkIsAuthenticated();
    }
    
    public function all()
    {
        $this->checkScopes(['pak.manage.questionnaire']);

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

        $conditions = "";

        if (!empty($params['keyword'])) {
            $conditions .= "nama like '%" . $params['keyword'] . "%' ";
        }

        $all = PAKQuestionnaire::find(['conditions' => $conditions]);
        $total_record = count($all);
        $rows = PAKQuestionnaire::find([
                    'conditions' => $conditions,
                    'limit' => $params['limit'],
                    'offset' => $params['offset']
        ])->toArray();

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

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

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

        $conditions = "deleted_at IS NULL";

        if (!empty($params['keyword'])) {
            $conditions .= " AND nama like '%" . $params['keyword'] . "%' ";
        }
        
        if (!empty($params['is_active'])) {
            $conditions .= " AND is_active = " . $params['is_active'];
        }

        $sort = 'ASC';
        if(!empty($params['sort'])) {
            $sort = $params['sort'];
        }

        $all = PAKQuestionnaire::find(['conditions' => $conditions]);
        $total_record = count($all);
        $result = PAKQuestionnaire::query()
            ->columns("Jaga\Models\PAK\PAKQuestionnaire.id, nama, deskripsi, Jaga\Models\PAK\PAKQuestionnaire.created_at, created_by, updated_at, updated_by, deleted_at, nama_dokumen, is_using_doc_info, is_active, questionnaire_category_id, title as category_name, views_order")
            ->leftJoin('Jaga\Models\PAK\PAKQuestionnaireCategory', 'Jaga\Models\PAK\PAKQuestionnaire.questionnaire_category_id = Jaga\Models\PAK\PAKQuestionnaireCategory.id')
            ->conditions($conditions)
            ->limit($params['limit'], $params['offset'])
            ->orderBy('views_order ' . $sort . ', nama ' . $sort)
            ->execute()
            ->toArray();

        $questionnaireIds = [];

        foreach ($result as $idx => $item) {
            $pakQuestJenisDoc = PAKJenisDokumenQuestionnaire::find([
                'conditions' => 'questionnaire_id = ?0 AND deleted_at IS NULL',
                'bind' => [
                    $item['id']
                ]
            ]);
            $result[$idx]['total_documents'] = $pakQuestJenisDoc->count();
            $result[$idx]['documents'] = $pakQuestJenisDoc->toArray();
        }

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

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

        $model = PAKQuestionnaire::findOrFail($id);
        $result = $model->getDetail();
        return new CollectionPaginatedResponse([$result]);
    }

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

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validateCreateAndUpdateRequest($rawBody);
        $params['created_by'] = $this->userID;
        $params['is_active'] = true;

        $docs = $params['documents'];
        unset($params['documents']);

        $model = new PAKQuestionnaire();
        $model->assign($params);
        $saved = $model->save();

        if (!$saved) {
            $this->throwValidationException($model->getMessages());
        } else {
            $this->saveDocs($model->id, $docs);

            $result = PAKQuestionnaire::query()
                ->columns("Jaga\Models\PAK\PAKQuestionnaire.id, nama, deskripsi, Jaga\Models\PAK\PAKQuestionnaire.created_at, created_by, updated_at, updated_by, deleted_at, nama_dokumen, is_using_doc_info, is_active, questionnaire_category_id, title as category_name, views_order")
                ->leftJoin('Jaga\Models\PAK\PAKQuestionnaireCategory', 'Jaga\Models\PAK\PAKQuestionnaire.questionnaire_category_id = Jaga\Models\PAK\PAKQuestionnaireCategory.id')
                ->conditions('Jaga\Models\PAK\PAKQuestionnaire.id = ?0')
                ->bind([$model->id])
                ->orderBy('views_order ASC, nama ASC')
                ->execute()
                ->toArray();

            return new CollectionPaginatedResponse($result);
        }
    }

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

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

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validateCreateAndUpdateRequest($rawBody);
        $params['updated_by'] = $this->userID;

        $docs = $params['documents'];
        unset($params['documents']);

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

        if (!$saved) {
            $this->throwValidationException($model->getMessages());
        } else {
            $this->saveDocs($model->id, $docs, 'update');

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

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

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

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

        $activated = $model->save(
            [
                'is_active' => true,
                'updated_by' => $this->userID
            ]
        );

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

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

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

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

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

        $deactivated = $model->save(
            [
                'is_active' => false,
                'updated_by' => $this->userID
            ]
        );

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

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


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

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

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

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

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

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

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

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

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

        $this->db->delete("pak_jenis_dokumen_questionnaire", "questionnaire_id=".$id);

        $deleted = $model->forceDelete();

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

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

    public function restore($id)
    {
        $this->checkScopes(['pak.manage.questionnaire']);
        
        $rawBody = $this->request->getJsonRawBody(true);
        $this->validateDeleteAndRestoreRequest($rawBody, $id);

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

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

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

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


    protected function saveDocs($questionnaire_id, $docs, $scenario = 'create')
    {
        $existings = PAKJenisDokumenQuestionnaire::find([
            'conditions' => 'questionnaire_id = :questionnaire_id:',
            'bind' => ['questionnaire_id' => $questionnaire_id]
        ]);

        $docIds = array_column($docs, 'id');

        if (count($existings) > 0) {
            foreach ($existings as $existing) {
                if (!in_array($existing->id, $docIds)) {
                    $existing->delete();
                }
            }
        }
        foreach ($docs as $key => $doc) {
            $model = PAKJenisDokumenQuestionnaire::firstOrCreate([
                'conditions' => 'id = :id:',
                'bind' => ['id' => $doc['id']]
            ]);
            $model->assign($doc);
            $model->questionnaire_id = $questionnaire_id;
            $model->save();
        }
    }

    protected function validateIndexRequest($request)
    {
        $request['limit'] = array_key_exists('limit', $request) ? $request['limit'] : 6;
        $request['offset'] = array_key_exists('offset', $request) ? $request['offset'] : 0;
        $request['keyword'] = array_key_exists('keyword', $request) ? $request['keyword'] : '';
        $request['order_by'] = array_key_exists('order_by', $request) ? strtolower($request['order_by']) : 'id';
        $request['order_direction'] = array_key_exists('order_direction', $request) ? strtolower($request['order_direction']) : 'asc';
        $request['is_active'] = array_key_exists('is_active', $request) ? $request['is_active'] : null;

        $allowed_order = ['id', 'nama'];
        $allowed_order_direction = ['asc', 'desc'];

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

        return $params;
    }

    protected function validateCreateAndUpdateRequest($request)
    {
        $rules = [
            'nama' => ['validators' => [
                'required', 
                [
                    'name' => 'max_string',
                    'params' => 255
                ]
            ]],
            'deskripsi' => ['validators' => []],
            'nama_dokumen' => ['validators' => [
                [
                    'name' => 'max_string',
                    'params' => 255
                ]
            ]],
            'is_using_doc_info' => ['validators' => []],
            'questionnaire_category_id' => ['validators' => []],
        ];

        $doc_rules = [
            'id' => ['validators' => ['digit']],
            'jenis_dokumen' => ['validators' => [
                'required', 
                [
                    'name' => 'max_string',
                    'params' => 255
                ]
            ]],
            'is_using_doc_info' => ['validators' => []],
        ];

        $doc_params = [];
        $doc_request = array_key_exists('documents', $request) ? $request['documents'] : null;

        if (!empty($doc_request)) {
            
            foreach ($doc_request as $key => $dr) {
                $valid = $this->filterExpectedRequest($dr, $doc_rules);
                array_push($doc_params, $valid);
            }    
        }
        
        $params = $this->filterExpectedRequest($request, $rules);
        $params['documents'] = $doc_params;

        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;
    }
}