<?php

namespace App\Models\Panel\Ujian;

use App\Models\Panel\BankSoal;
use CodeIgniter\Model;

class Hasil extends Model
{
    protected $DBGroup              = 'default';
    protected $table                = 'ujian_siswa';
    protected $primaryKey           = 'id';
    protected $useAutoIncrement     = true;
    protected $insertID             = 0;
    protected $returnType           = 'array';
    protected $useSoftDeletes       = false;
    protected $protectFields        = true;
    protected $allowedFields        = [
        'jadwal_id', 'siswa_id', 'status', 'pg_benar', "jwt", 'pgmulti_benar', 'pgcouple_benar', 'total_pg', 'total_shortentry', 'nilai_pg', 'nilai_esai', 'ip_address', 'start_at', 'end_at'
    ];

    // Dates
    protected $useTimestamps        = false;
    protected $dateFormat           = 'datetime';
    protected $createdField         = 'created_at';
    protected $updatedField         = 'updated_at';
    protected $deletedField         = 'deleted_at';

    // Validation
    protected $validationRules      = [];
    protected $validationMessages   = [];
    protected $skipValidation       = false;
    protected $cleanValidationRules = true;

    // Callbacks
    protected $allowCallbacks       = true;
    protected $beforeInsert         = [];
    protected $afterInsert          = [];
    protected $beforeUpdate         = [];
    protected $afterUpdate          = [];
    protected $beforeFind           = [];
    protected $afterFind            = [];
    protected $beforeDelete         = [];
    protected $afterDelete          = [];

    public function reset($id, $jadwalId = null)
    {
        $where['id'] = $id;
        if ($jadwalId) $where['jadwal_id'] = $jadwalId;
        $data = $this->db->table("ujian_siswa")->where($where)->get()->getRowArray();
        if (!$data) return false;
        $this->db->transStart();
        $this->db->table("ujian_siswa")->where($where)->delete();
        $this->db->table("ujian_siswa")->insert([
            'jadwal_id' => $data['jadwal_id'],
            'siswa_id' => $data['siswa_id'],
        ]);
        $this->db->transComplete();
        return !($this->db->transStatus() === FALSE);
    }
    public function reset_batch($id, $jadwalId = null)
    {
        $data = $this->db->table("ujian_siswa")->select('jadwal_id,siswa_id')->whereIn('id', $id);
        if ($jadwalId) {
            $data->where(['jadwal_id' => $jadwalId]);
        }
        $data = $data->get()->getResultArray();
        if (!$data) return false;
        $this->db->transStart();
        $builder =        $this->db->table("ujian_siswa");
        if ($jadwalId) {
            $builder->where('jadwal_id', $jadwalId);
        }
        $builder->whereIn('id', $id)->delete();
        $this->db->table("ujian_siswa")->insertBatch($data);
        $this->db->transComplete();
        return !($this->db->transStatus() === FALSE);
    }
    public function unlock_batch($id, $jadwalId = null)
    {
        $data = $this->db->table("ujian_siswa")->whereIn('id', $id)->get()->getRowArray();
        if (!$data) return false;
        if ($jadwalId) $where['jadwal_id'] = $jadwalId;
        $this->db->transStart();
        $jwt = $this->db->table("ujian_siswa");
        if ($where) $jwt->where($where);
        $jwt->whereIn('id', $id);
        $jwt->set('jwt', null)->update();
        $this->db->transComplete();
        return !($this->db->transStatus() === FALSE);
    }
    public function unlock($id, $jadwalId = null)
    {
        $where['id'] = $id;
        $data = $this->db->table("ujian_siswa")->where($where)->get()->getRowArray();
        if (!$data) return false;
        if ($jadwalId) $where['jadwal_id'] = $jadwalId;
        $this->db->transStart();
        $this->db->table("ujian_siswa")->where($where)->set('jwt', null)->update();
        $this->db->transComplete();
        return !($this->db->transStatus() === FALSE);
    }

    public function finish($id, $jadwal_id = null, $opt = [])
    {
        $jadwalModel = (new Jadwal());
        $data = $jadwalModel->progress($jadwal_id, $id, $opt, true);
        if (!$data) return false;
        $now = time();
        $batch = [];
        if (isset($data[0])) {
            foreach ($data as $key => $d) {
                $n = [
                    "id" => $d['id'],
                    "status" => '2',
                    "pg_benar" => $d['soal_pg_benar'],
                    "pgmulti_benar" => $d['soal_pgmulti_benar'],
                    "pgtf_benar" => $d['soal_pgtf_benar'],
                    "pgcouple_benar" => $d['soal_pgcouple_benar'],
                    "shortentry_benar" => $d['soal_shortentry_benar'],
                    "total_pg" => $d['visible_pg'] + $d['visible_pgmulti'] + $d['visible_pgtf'] + $d['visible_pgcouple'],
                    "total_shortentry" => $d['visible_shortentry'],
                    "nilai_pg" => 0,
                    "nilai_esai" => 0,
                ];
                if ($d['status'] != '2') $n['end_at'] = $now;
                $tp = ($d['total_point_shortentry'] + $d['total_point_pgcommon'] + $d['total_point_pgmulti'] + $d['total_point_pgtf'] + $d['total_point_pgcouple']);
                $trp = (($d['total_true_default_point_shortentry'] ?? 0) + ($d['total_true_default_point_pgcommon'] ?? 0) + ($d['total_true_default_point_pgmulti'] ?? 0) + ($d['total_true_default_point_pgtf'] ?? 0) + ($d['total_true_default_point_pgcouple'] ?? 0));
                $n['nilai_pg'] = $tp <= 0 || $trp <= 0 ? 0 : ($tp / $trp) * $d['bobot_tf'];
                if ($d['soal_esai_nilai']) {
                    $n['nilai_esai'] = $d['soal_esai_nilai'] * ($d['bobot_esai'] / 100);
                }
                $batch[] = $n;
            }
        } else {
            $d = $data;
            $n = [
                "id" => $d['id'],
                "status" => '2',
                "pg_benar" => $d['soal_pg_benar'],
                "pgmulti_benar" => $d['soal_pgmulti_benar'],
                "pgtf_benar" => $d['soal_pgtf_benar'],
                "pgcouple_benar" => $d['soal_pgcouple_benar'],
                "shortentry_benar" => $d['soal_shortentry_benar'],
                "total_pg" => $d['visible_pg'] + $d['visible_pgmulti'] + $d['visible_pgtf'] + $d['visible_pgcouple'],
                "total_shortentry" => $d['visible_shortentry'],
                "nilai_pg" => 0,
                "nilai_esai" => 0,
            ];
            if ($d['status'] != '2') $n['end_at'] = $now;
            $tp = ($d['total_point_shortentry'] + $d['total_point_pgcommon'] + $d['total_point_pgmulti'] + $d['total_point_pgtf'] + $d['total_point_pgcouple']);
            $trp = (($d['total_true_default_point_shortentry'] ?? 0) + ($d['total_true_default_point_pgcommon'] ?? 0) + ($d['total_true_default_point_pgmulti'] ?? 0) + ($d['total_true_default_point_pgtf'] ?? 0) + ($d['total_true_default_point_pgcouple'] ?? 0));
            $n['nilai_pg'] =  $tp <= 0 || $trp <= 0 ? 0 : ($tp / $trp) * $d['bobot_tf'];
            if ($d['soal_esai_nilai']) {
                $n['nilai_esai'] = $d['soal_esai_nilai'] * ($d['bobot_esai'] / 100);
            }
            $batch[] = $n;
        }
        $this->db->transBegin();
        $this->db->table($this->table)->updateBatch($batch, 'id');
        $this->db->transComplete();
        if ($this->db->transStatus() === FALSE) {
            $this->db->transRollback();
            return false;
        }
        $this->db->transCommit();
        return true;
    }

    public function save_jawaban_pg($data, $ujian_id = null)
    {
        if (!isset($data[0])) {
            if ($ujian_id) {
                $data['ujian_id'] = $ujian_id;
            }
            $data = [$data];
        }
        $ujian_id = [];
        $this->db->transStart();
        foreach ($data as $key => $v) {
            $v = (array) $v;
            if (!in_array($v['ujian_id'], $ujian_id)) {
                $ujian_id[] = $v['ujian_id'];
            }
            $this->db->table('jawaban_pg_ujian_siswa')->delete(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']]);
            $this->db->table('jawaban_pg_ujian_siswa')->insert([
                'ujian_id' => $v['ujian_id'],
                'soal_id' => $v['soal_id'],
                'opsi_id' => $v['opsi_id'],
            ]);
        }
        $this->db->transComplete();
        if ($this->db->transStatus() === FALSE) return false;
        $ujian = $this->db->table('ujian_siswa')->whereIn('id', $ujian_id)->get()->getResultArray();
        foreach ($ujian as $key => $v) {
            if ($v['status'] == 2) {
                $state = $this->finish($v['id']);
                if (!$state) return false;
            }
        }
        return true;
    }
    public function save_jawaban_pgmulti($data, $ujian_id = null)
    {
        if (!isset($data[0])) {
            if ($ujian_id) {
                $data['ujian_id'] = $ujian_id;
            }
            $data = [$data];
        }
        $ujian_id = [];
        $this->db->transStart();
        foreach ($data as $key => $v) {
            $v = (array) $v;
            if (!in_array($v['ujian_id'], $ujian_id)) {
                $ujian_id[] = $v['ujian_id'];
            }
            $v['opsi'] = array_unique($v['opsi']);
            $opsi = [];
            foreach ($v['opsi'] as $opsi_id) {
                if ($opsi_id) {
                    $opsi[] = [
                        'ujian_id' => $v['ujian_id'],
                        'soal_id' => $v['soal_id'],
                        'opsi_id' => $opsi_id,
                    ];
                }
            }
            if (!$opsi) {
                $lastOpsi = $this->db->table('jawaban_pgmulti_ujian_siswa')->getWhere(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']])->getRowArray();
                if ($lastOpsi) $opsi[] = [
                    'ujian_id' => $lastOpsi['ujian_id'],
                    'soal_id' => $lastOpsi['soal_id'],
                ];
            }
            $this->db->table('jawaban_pgmulti_ujian_siswa')->delete(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']]);
            if ($opsi) $this->db->table('jawaban_pgmulti_ujian_siswa')->insertBatch($opsi);
        }
        $this->db->transComplete();
        if ($this->db->transStatus() === FALSE) {
            return false;
        }
        $ujian = $this->db->table('ujian_siswa')->whereIn('id', $ujian_id)->get()->getResultArray();
        foreach ($ujian as $key => $v) {
            if ($v['status'] == 2) {
                $state = $this->finish($v['id']);
                if (!$state) return false;
            }
        }
        return true;
    }
    public function save_jawaban_pgtf($data, $ujian_id = null)
    {
        if (!isset($data[0])) {
            if ($ujian_id) {
                $data['ujian_id'] = $ujian_id;
            }
            $data = [$data];
        }
        $ujian_id = [];
        $this->db->transStart();
        foreach ($data as $key => $v) {
            $v = (array) $v;
            if (!in_array($v['ujian_id'], $ujian_id)) {
                $ujian_id[] = $v['ujian_id'];
            }
            $v['opsi'] = array_unique($v['opsi']);
            $opsi = [];
            foreach ($v['opsi'] as $opsi_id) {
                if ($opsi_id) {
                    $opsi[] = [
                        'ujian_id' => $v['ujian_id'],
                        'soal_id' => $v['soal_id'],
                        'opsi_id' => explode('-', $opsi_id)[0] ?? null,
                        'tf' => explode('-', $opsi_id)[1] ?? null,
                    ];
                }
            }
            if (!$opsi) {
                $lastOpsi = $this->db->table('jawaban_pgtf_ujian_siswa')->getWhere(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']])->getRowArray();
                if ($lastOpsi) $opsi[] = [
                    'ujian_id' => $lastOpsi['ujian_id'],
                    'soal_id' => $lastOpsi['soal_id'],
                ];
            }
            $this->db->table('jawaban_pgtf_ujian_siswa')->delete(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']]);
            if ($opsi) $this->db->table('jawaban_pgtf_ujian_siswa')->insertBatch($opsi);
        }
        $this->db->transComplete();
        if ($this->db->transStatus() === FALSE) {
            return false;
        }
        $ujian = $this->db->table('ujian_siswa')->whereIn('id', $ujian_id)->get()->getResultArray();
        foreach ($ujian as $key => $v) {
            if ($v['status'] == 2) {
                $state = $this->finish($v['id']);
                if (!$state) return false;
            }
        }
        return true;
    }
    public function save_jawaban_pgcouple($data, $ujian_id = null)
    {
        if (!isset($data[0])) {
            if ($ujian_id) {
                $data['ujian_id'] = $ujian_id;
            }
            $data = [$data];
        }
        $ujian_id = [];
        $this->db->transStart();
        foreach ($data as $key => $v) {
            $v = (array) $v;
            if (!in_array($v['ujian_id'], $ujian_id)) {
                $ujian_id[] = $v['ujian_id'];
            }
            $v['opsi'] = array_unique($v['opsi']);
            $opsi = [];
            foreach ($v['opsi'] as $opsi_id) {
                if ($opsi_id) {
                    $opsi_id = explode('-', $opsi_id);
                    $opsi[] = [
                        'ujian_id' => $v['ujian_id'],
                        'soal_id' => $v['soal_id'],
                        'couple_id' => $opsi_id[0],
                        'opsi_id' => $opsi_id[1],
                    ];
                }
            }
            if (!$opsi) {
                $lastOpsi = $this->db->table('jawaban_pgcouple_ujian_siswa')->getWhere(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']])->getRowArray();
                if ($lastOpsi) $opsi[] = [
                    'ujian_id' => $lastOpsi['ujian_id'],
                    'soal_id' => $lastOpsi['soal_id'],
                ];
            }
            $this->db->table('jawaban_pgcouple_ujian_siswa')->delete(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']]);

            if ($opsi) $this->db->table('jawaban_pgcouple_ujian_siswa')->insertBatch($opsi);
        }
        $this->db->transComplete();
        if ($this->db->transStatus() === FALSE) {
            return false;
        }
        $ujian = $this->db->table('ujian_siswa')->whereIn('id', $ujian_id)->get()->getResultArray();
        foreach ($ujian as $key => $v) {
            if ($v['status'] == 2) {
                $state = $this->finish($v['id']);
                if (!$state) return false;
            }
        }
        return true;
    }
    public function save_jawaban_shortentry($data, $ujian_id = null)
    {
        if (!isset($data[0])) {
            if ($ujian_id) {
                $data['ujian_id'] = $ujian_id;
            }
            $data = [$data];
        }
        $ujian_id = [];
        $this->db->transStart();
        foreach ($data as $key => $v) {
            $v = (array) $v;
            if (!in_array($v['ujian_id'], $ujian_id)) {
                $ujian_id[] = $v['ujian_id'];
            }
            $this->db->table('jawaban_shortentry_ujian_siswa')->set('respond', $v['respond'])->where(['ujian_id' => $v['ujian_id'], 'soal_id' => $v['soal_id']])->update();
        }
        $this->db->transComplete();
        if ($this->db->transStatus() === FALSE) {
            return false;
        }
        $ujian = $this->db->table('ujian_siswa')->whereIn('id', $ujian_id)->get()->getResultArray();
        foreach ($ujian as $key => $v) {
            if ($v['status'] == 2) {
                $state = $this->finish($v['id']);
                if (!$state) return false;
            }
        }
        return true;
    }
    public function save_jawaban_esai($data, $ujian_id = null)
    {
        if (!isset($data[0])) {
            if ($ujian_id) {
                $data['ujian_id'] = $ujian_id;
            }
            $data = [$data];
        }
        $nilai = [];
        $this->db->transStart();
        foreach ($data as $key => $value) {
            $value = (array)$value;
            if (isset($value['nilai'])) {
                if (!isset($nilai[$value['ujian_id']])) {
                    $nilai[$value['ujian_id']] = ['nilai' => 0];
                }
                $nilai[$value['ujian_id']]['nilai'] += (float)$value['nilai'];
            };
            $where['ujian_id'] = $value['ujian_id'];
            $where['soal_id'] = $value['soal_id'];
            unset($value['ujian_id']);
            unset($value['soal_id']);
            $this->db->table('jawaban_esai_ujian_siswa')->where($where)->update($value);
        }
        foreach ($nilai as $key => $v) {
            $draft = $this->db->table('draft_ujian du');
            $draft->join('jadwal_ujian ju', 'ju.draft_id=du.id');
            $draft->join('ujian_siswa us', 'us.jadwal_id=ju.id');
            $draft->select('du.*');
            $draft->where('us.id', $key);
            $draft = $draft->get()->getRowArray();
            $this->db->table('ujian_siswa')->update(['nilai_esai' => $v['nilai'] * ($draft['bobot_esai'] / 100)], ['id' => $key]);
        }
        $this->db->transComplete();
        return !($this->db->transStatus() === FALSE);
    }
    public function jawaban_pg($ujian_id, $jadwal_id = null)
    {
        $this->select("$this->table.id,$this->table.status status_ujian,jpus.opsi_id,jpus.soal_id,soal_data.question");
        $this->join('jawaban_pg_ujian_siswa jpus', "jpus.ujian_id=$this->table.id");
        $this->join('soal_data', 'soal_data.id=jpus.soal_id');
        $this->where(['soal_data.jenis_soal' => (new BankSoal())->jenis('pg'), "$this->table.id" => $ujian_id]);
        if ($jadwal_id) $this->where("$this->table.jadwal_id", $jadwal_id);
        $this->orderBy('jpus.created_at', 'ASC');
        return $this->findAll();
    }
    public function jawaban_esai($ujian_id, $jadwal_id = null)
    {
        $this->select("$this->table.id,$this->table.status status_ujian,jeus.soal_id,soal_data.question,jeus.esai,jeus.nilai");
        $this->join('jawaban_esai_ujian_siswa jeus', "jeus.ujian_id=$this->table.id");
        $this->join('soal_data', 'soal_data.id=jeus.soal_id');
        $this->where(['soal_data.jenis_soal' => (new BankSoal())->jenis('esai'), "$this->table.id" => $ujian_id]);
        if ($jadwal_id) $this->where("$this->table.jadwal_id", $jadwal_id);
        $this->orderBy('jeus.created_at', 'ASC');
        return $this->findAll();
    }
    public function jawaban_shortentry($ujian_id, $jadwal_id = null, $withCorrectAnswer = false)
    {
        $select = ["$this->table.id,$this->table.status status_ujian,(CASE WHEN REPLACE(LOWER(jsus.respond),' ','')=REPLACE(LOWER(soal_data.shortentry),' ','') THEN soal_data.true_default_point ELSE soal_data.false_default_point END) nilai,jsus.soal_id,soal_data.question,jsus.respond"];
        if ($withCorrectAnswer) $select[] = "soal_data.shortentry correct_answer";
        $this->select(implode(',', $select));
        $this->join('jawaban_shortentry_ujian_siswa jsus', "jsus.ujian_id=$this->table.id");
        $this->join('soal_data', 'soal_data.id=jsus.soal_id');
        $this->where(['soal_data.jenis_soal' => (new BankSoal())->jenis('shortentry'), "$this->table.id" => $ujian_id]);
        if ($jadwal_id) $this->where("$this->table.jadwal_id", $jadwal_id);
        $this->orderBy('jsus.created_at', 'ASC');
        return $this->findAll();
    }
    public function jawaban_pgmulti($ujian_id, $jadwal_id = null)
    {
        $this->select("$this->table.id,$this->table.status status_ujian,GROUP_CONCAT(jpus.opsi_id) opsi,jpus.soal_id,soal_data.question");
        $this->join('jawaban_pgmulti_ujian_siswa jpus', "jpus.ujian_id=$this->table.id");
        $this->join('soal_data', 'soal_data.id=jpus.soal_id');
        $this->where(['soal_data.jenis_soal' => (new BankSoal())->jenis('pgmulti'), "$this->table.id" => $ujian_id]);
        if ($jadwal_id) $this->where("$this->table.jadwal_id", $jadwal_id);
        $this->orderBy('jpus.created_at', 'ASC');
        $this->groupBy('jpus.soal_id');
        return $this->findAll();
    }
    public function jawaban_pgtf($ujian_id, $jadwal_id = null)
    {
        $this->select("$this->table.id,$this->table.status status_ujian,GROUP_CONCAT(jpus.opsi_id,'-',jpus.tf) opsi,jpus.soal_id,soal_data.question");
        $this->join('jawaban_pgtf_ujian_siswa jpus', "jpus.ujian_id=$this->table.id");
        $this->join('soal_data', 'soal_data.id=jpus.soal_id');
        $this->where(['soal_data.jenis_soal' => (new BankSoal())->jenis('pgtf'), "$this->table.id" => $ujian_id]);
        if ($jadwal_id) $this->where("$this->table.jadwal_id", $jadwal_id);
        $this->orderBy('jpus.created_at', 'ASC');
        $this->groupBy('jpus.soal_id');
        return $this->findAll();
    }
    public function jawaban_pgcouple($ujian_id, $jadwal_id = null)
    {
        $this->select("$this->table.id,$this->table.status status_ujian,GROUP_CONCAT(CONCAT(jpus.couple_id,'-',jpus.opsi_id)) opsi,jpus.soal_id,soal_data.question");
        $this->join('jawaban_pgcouple_ujian_siswa jpus', "jpus.ujian_id=$this->table.id");
        $this->join('soal_data', 'soal_data.id=jpus.soal_id');
        $this->where(['soal_data.jenis_soal' => (new BankSoal())->jenis('pgcouple'), "$this->table.id" => $ujian_id]);
        if ($jadwal_id) $this->where("$this->table.jadwal_id", $jadwal_id);
        $this->orderBy('jpus.created_at', 'ASC');
        $this->groupBy('jpus.soal_id');
        return $this->findAll();
    }

    public function get_soal_couple($soal_id)
    {
        $builder = $this->db->table("soal_data_couple");
        $select = 'soal_data_couple.id,soal_data_couple.soal_id,soal_data_couple.body';
        $builder->select($select);
        if (is_array($soal_id)) {
            $builder->whereIn("soal_id", $soal_id);
        } else {
            $builder->where("soal_id", $soal_id);
        }
        return $builder->get()->getResultArray();
    }
    public function get_soal_opsi($soal_id, $withKey = false)
    {
        $builder = $this->db->table("soal_opsi");
        $select = 'soal_opsi.id,soal_opsi.soal_id,soal_opsi.body';
        if ($withKey) $select .= ",soal_opsi.soal_couple_id couple_id,soal_opsi.is_key";
        $builder->select($select);
        if (is_array($soal_id)) {
            $builder->whereIn("soal_id", $soal_id);
        } else {
            $builder->where("soal_id", $soal_id);
        }
        return $builder->get()->getResultArray();
    }
}
