<?php

use Jaga\Models\BaseModel;
use Jaga\Traits\JagaTimestamp;
use Jaga\Traits\SoftDelete;

/**
 * Class PancekFormulir
 * @property PancekInstansi $instansi
 * @property PancekAnswer[] $answers
 * @property UmUser $reviewer
 * @property UmUser $verifier
 */
class PancekFormulir extends BaseModel
{
    use JagaTimestamp, SoftDelete;

    public $id;
    public $instansi_id;
    public $periode;
    public $jumlah_revisi;
    public $keterangan;
    public $status;
    public $created_at;
    public $updated_at;
    public $deleted_at;
    public $reviewed_at;
    public $reviewed_by;
    public $verified_at;
    public $verified_by;
    public $kppbc_um_id;
    public $kppbc_verify_start_date;
    public $kppbc_verify_end_date;

    protected $countAnswer;
    protected $countAnswered;
    protected $countVerified;
    protected $answeredPercentage;
    protected $verifiedPercentage;
    protected $ksp;

    const STATUS_NEW                = 'NEW';
    const STATUS_DRAFT              = 'DRAFT';
    const STATUS_NEED_TO_REVIEW     = 'NEED_TO_REVIEW';
    const STATUS_REVIEW_IN_PROGRESS = 'REVIEW_IN_PROGRESS';
    const STATUS_REVIEWED           = 'REVIEWED';
    const STATUS_VERIFIED           = 'VERIFIED';

    const MINIMUM_PERCENTAGE_TO_DOWNLOAD = 75;

    public function initialize()
    {
        $this->setSchema("jaga");
        $this->setSource("pancek_formulir");

        $this->belongsTo(
            'instansi_id',
            \PancekInstansi::class,
            'id',
            [
                'reusable' => true, // cache related data
                'alias' => 'instansi',
                'params' => [
                    'conditions' => 'deleted_at IS NULL'
                ],
            ]
        );

        $this->hasMany(
            'id',
            \PancekAnswer::class,
            'formulir_id',
            [
                'reusable' => true, // cache related data
                'alias' => 'answers',
                'params' => [
                    'conditions' => 'deleted_at IS NULL',
                    'order' => 'id ASC'
                ],
            ]
        );

        $this->belongsTo(
            'reviewed_by',
            \UmUser::class,
            'um_id',
            [
                'reusable' => true, // cache related data
                'alias' => 'reviewer'
            ]
        );

        $this->belongsTo(
            'verified_by',
            \UmUser::class,
            'um_id',
            [
                'reusable' => true, // cache related data
                'alias' => 'verifier'
            ]
        );

        $this->belongsTo(
            'kppbc_um_id',
            \UmUser::class,
            'um_id',
            [
                'reusable' => true, // cache related data
                'alias' => 'kppbc_verifikator'
            ]
        );
    }

    /**
     * @param $instansiId
     * @return PancekFormulir|null
     */
    public static function findActiveByInstansiId($instansiId)
    {
        $formulirs = self::find([
            'conditions' => 'instansi_id = :instansi_id: AND deleted_at IS NULL',
            'bind' => ['instansi_id' => $instansiId]
        ]);

        $res = null;
        foreach ($formulirs as $formulir) {
            /** @var $formulir PancekFormulir */
            if (!$formulir->isExpired()) {
                $res = $formulir;
            }
        }

        return $res;
    }

    public function getForm()
    {
        $res = $this->toArray();
        $res['reviewed_by_name'] = $res['verified_by_name'] = null;
        if (!empty($this->reviewed_by) && $this->reviewer) {
            $res['reviewed_by_name'] = $this->reviewer->nama;
        }
        if (!empty($this->verified_by) && $this->verifier) {
            $res['verified_by_name'] = $this->verifier->nama;
        }
        $res['instansi'] = $this->instansi;
        $res['answered'] = $this->countAnswered();
        $res['answer'] = $this->countAnswer();
        $res['is_active'] = !$this->isExpired();
        $scorePerKSP = $this->scorePerKSP();
        $answers = [];
        foreach ($this->answers as $answer) {
            $answers[$answer->komponen_indikator_id] = $answer->getDetail();
        }
//        $res['form'] = (new PancekKonsepSistemPencegahan)->getForm(['conditions' => 'deleted_at IS NULL AND formulir_type = :tipe:', 'bind' => ['tipe' => $this->instansi->jenisInstansi->formulir_type]]);
        $res['form'] = (new PancekKonsepSistemPencegahan)->getFormByFormulir($this);
        foreach ($res['form'] as $kspKey => $ksp) {
            $res['form'][$kspKey]['score'] = $scorePerKSP[$ksp['id']]['score'];
            foreach ($ksp['indikators'] as $iKey => $i) {
                $res['form'][$kspKey]['indikators'][$iKey]['score'] = 0;
                foreach ($i['komponens'] as $kKey => $k) {
                    if (!$k['is_header']) {
                        $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['answer'] = $answers[$k['id']];
                        $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['answer']['score'] = 0;
                        if (sizeof($answers[$k['id']]['attachments']) > 0) {
                            if($answers[$k['id']]['verify_status'] == null || $answers[$k['id']]['verify_status'] == PancekAnswer::VERIFY_STATUS_DISETUJUI || $answers[$k['id']]['verify_status'] == PancekAnswer::VERIFY_STATUS_UPDATED || $answers[$k['id']]['verify_status'] == PancekAnswer::VERIFY_STATUS_REVISED) {
                                $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['answer']['score'] = doubleval(strval($k['bobot']));
                                $res['form'][$kspKey]['indikators'][$iKey]['score'] += $k['bobot'];
                            }
                        }
                    } else {
                        $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['score'] = 0;
                        foreach ($k['subkomponens'] as $skKey => $sk) {
                            $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['subkomponens'][$skKey]['answer'] = $answers[$sk['id']];
                            $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['subkomponens'][$skKey]['answer']['score'] = 0;
                            if (sizeof($answers[$sk['id']]['attachments']) > 0) {
                                if(array_key_exists($k['id'], $answers)) {
                                    if ($answers[$k['id']]['verify_status'] == null || $answers[$k['id']]['verify_status'] == PancekAnswer::VERIFY_STATUS_DISETUJUI || $answers[$k['id']]['verify_status'] == PancekAnswer::VERIFY_STATUS_UPDATED || $answers[$k['id']]['verify_status'] == PancekAnswer::VERIFY_STATUS_REVISED) {
                                        $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['subkomponens'][$skKey]['answer']['score'] = doubleval(strval($sk['bobot']));
                                        $res['form'][$kspKey]['indikators'][$iKey]['komponens'][$kKey]['score'] += $sk['bobot'];
                                        $res['form'][$kspKey]['indikators'][$iKey]['score'] += $sk['bobot'];
                                    }
                                }
                            }
                        }
                    }
                }
                $res['form'][$kspKey]['indikators'][$iKey]['score'] = doubleval(strval($res['form'][$kspKey]['indikators'][$iKey]['score']));
            }
        }
        $res['max_revision'] = getenv('PANCEK_FORMULIR_MAX_REVISION');
        $res['remaining_sla_days'] = null;
        if($res['kppbc_verify_end_date'] != null) {
            $endSlaDate = new DateTime($res['kppbc_verify_end_date']);
            $today = new DateTime();
            $interval = $endSlaDate->diff($today);
            $daysDifferent  = $interval->days;
            if($interval->invert == 0) {
                $daysDifferent = -1 * $daysDifferent;
            }
            $res['remaining_sla_days'] = $daysDifferent;
        }

        return $res;
    }

    public function isExpired()
    {
        return $this->created_at <= date('Y-m-d', strtotime('-' . getenv("PANCEK_FORMULIR_VALIDITY_PERIOD") . ' year'));
    }

    public function isExceedRevisionLimit()
    {
        return $this->jumlah_revisi >= getenv("PANCEK_FORMULIR_MAX_REVISION");
    }

    public function countAnswered()
    {
        $answered = 0;
        foreach ($this->answers as $answer) {
            if (sizeof($answer->attachments) > 0) {
                $answered += 1;
            }
        }

        return $answered;
    }

    public function countAnswer()
    {
        return sizeof($this->answers);
    }

    public function scorePerKSP()
    {
        $ksp = [];
        foreach ($this->answers as $answer)
        {
            $konsepSistemPencegahan = $answer->komponenIndikator->indikator->konsepSistemPencegahan;
            if (!array_key_exists($konsepSistemPencegahan->id, $ksp)) {
                $ksp[$konsepSistemPencegahan->id] = [
                    'code' => $konsepSistemPencegahan->code,
                    'label' => $konsepSistemPencegahan->label,
                    'label_en' => $konsepSistemPencegahan->label_en,
                    'score' => 0,
                    'score_verified' => 0,
                    'answer' => 0,
                    'answered' => 0,
                    'verified' => 0
                ];
            }
            if (!$answer->komponenIndikator->is_header) {
                $ksp[$konsepSistemPencegahan->id]['answer'] += 1;
                if (sizeof($answer->attachments) > 0) {
                    if($answer->verify_status == null || $answer->verify_status == PancekAnswer::VERIFY_STATUS_UPDATED || $answer->verify_status == PancekAnswer::VERIFY_STATUS_REVISED || $answer->verify_status == PancekAnswer::VERIFY_STATUS_DISETUJUI) {
                        $ksp[$konsepSistemPencegahan->id]['score'] += $answer->komponenIndikator->bobot;
                        $ksp[$konsepSistemPencegahan->id]['answered'] += 1;
                    }
                    if($answer->verify_status == PancekAnswer::VERIFY_STATUS_DISETUJUI) {
                        $ksp[$konsepSistemPencegahan->id]['score_verified'] += $answer->komponenIndikator->bobot;
                        $ksp[$konsepSistemPencegahan->id]['verified'] += 1;
                    }
                }
            }
        }

        foreach ($ksp as $key => $value) {
            $ksp[$key]['score'] = doubleval(strval($ksp[$key]['score']));
        }

        return $ksp;
    }

    public function stat($columns = null)
    {
        $res = $this->toArray($columns);
        $stat = $this->scorePerKSP();
        $res['score'] = 0;
        $res['stat'] = $stat;
        if (sizeof($stat) > 0) {
            $res['score'] = array_sum(array_column($stat, 'score')) / sizeof($stat);
        }

        return $res;
    }

    public function getDetail($withScores = false)
    {
        $res = $this->toArray();
        $res['reviewed_by_name'] = $res['verified_by_name'] = null;
        if (!empty($this->reviewed_by) && $this->reviewer) {
            $res['reviewed_by_name'] = $this->reviewer->nama;
        }
        if (!empty($this->verified_by) && $this->verifier) {
            $res['verified_by_name'] = $this->verifier->nama;
        }
        $res['instansi'] = $this->instansi;
        $res['is_active'] = !$this->isExpired();
        if ($withScores) {
            $res['answered'] = $this->countAnswered();
            $res['answer'] = $this->countAnswer();
            $res['scores'] = $this->scorePerKSP();
        }

        return $res;
    }

    public function isDownloadAvailable(): bool
    {
        if($this->countAnswer == null) {
            $this->getCountAndScoreKSP();
        }

        $isAvailable = true;
        foreach ($this->ksp as $item) {
//            $percentage = $item['answer'] > 0 ? ($item['answered'] / $item['answer']) * 100 : 0;
            $percentage = $item['score'];
            if ($percentage <= self::MINIMUM_PERCENTAGE_TO_DOWNLOAD) {
                $isAvailable = false;
                break;
            }
        }

        return $isAvailable && $this->answeredPercentage > self::MINIMUM_PERCENTAGE_TO_DOWNLOAD;
    }

    public function isDownloadVerifiedAvailable(): bool
    {
        if($this->countAnswer == null) {
            $this->getCountAndScoreKSP();
        }

        $isAvailable = true;
        foreach ($this->ksp as $item) {
//            $percentageVerified = $item['answer'] > 0 ? ($item['verified'] / $item['answer']) * 100 : 0;
            $percentageVerified = $item['score_verified'];
            if ($percentageVerified <= self::MINIMUM_PERCENTAGE_TO_DOWNLOAD) {
                $isAvailable = false;
                break;
            }
        }

        return $isAvailable && $this->verifiedPercentage > self::MINIMUM_PERCENTAGE_TO_DOWNLOAD;
    }

    private function getCountAndScoreKSP()
    {

        $this->countAnswer = $this->countAnswer();
        $this->countAnswered = $this->countAnswered();
        $this->countVerified = $this->countVerified();

        $this->answeredPercentage = $this->countAnswer > 0 ? ($this->countAnswered / $this->countAnswer) * 100 : 0;
        $this->verifiedPercentage = $this->countAnswer > 0 ? ($this->countVerified / $this->countAnswer) * 100 : 0;

        $this->ksp = $this->scorePerKSP();
    }

    private function countVerified()
    {
        $verified = 0;
        foreach ($this->answers as $answer) {
            if($answer->verify_status == PancekAnswer::VERIFY_STATUS_DISETUJUI) {
                $verified += 1;
            }
        }

        return $verified;
    }
}
