<?php
use Phalcon\Queue\Beanstalk;

class StranasNewPeriodeController extends BaseController {
    public function index() {
        // $this->checkIsAuthenticated();
        $getParams = $this->request->get();

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

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

        $condition = 'deleted_at is null';
        $condition .= (isset($_GET['yearstrart']) && $_GET['yearstrart'] != '') ? ' and yearstrart = '.$_GET['yearstrart'] : '';

        $data = StranasNewPeriode::find([
            'conditions' => $condition,
            'limit' => $params['limit'],
            'offset' => $params['offset'],
            'order' => 'yearstart'
        ]);

        $total_record = StranasNewPeriode::count();

        return new PaginatedResponse($data, $total_record, $params['limit'], $params['offset']);
    }
    // C
    public function create() {
        $this->checkScopes(['stranas.admin']);

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validate( $rawBody, [ 
            'yearstart' => ['validators' => ['required', 'numeric']], 
            'level1' => ['validators' => ['required']], 
            'level2' => ['validators' => ['required']], 
            'level3' => ['validators' => []], 
            'level4' => ['validators' => []], 
            'is_active' => ['validators' => []], 
        ] );

        $tbl = new StranasNewPeriode();
        $tbl->yearstart = $params['yearstart'];
        $tbl->level1 = $params['level1'];
        $tbl->level2 = $params['level2'];
        $tbl->level3 = $params['level3'];
        $tbl->level4 = $params['level4'];
        $tbl->is_active = $params['is_active'];
        $tbl->level_count = ($params['level4'] != '') ? 4 : 3;
        $now = date('Y-m-d H:i:s');
        $tbl->created_at = $now;
        $tbl->created_by = $this->shared->user->um_id;
        $status = $tbl->save();

        if (!$status) {
            $errors = $tbl->getMessages();

            $error_messages = [];
            foreach ($errors as $key => $error) {
                $error_messages[] = ["field" => $error->getField(), "message" => $error->getMessage()];
            }
            throw new ValidationException($error_messages);
        } else {
            // add triwulan 
            $id_periode = $tbl->id;
            $query = "
                insert into jaga.str_periode_triwulan (id_periode, id_triwulan, label, started_at,ended_at,verification_started_at,verification_ended_at)
                select 
                    ".$id_periode." id_periode,
                    id as id_triwulan,
                    label,
                    case when id < 5 then started_at + MAKE_INTERVAL(YEARS := ".$params['yearstart']." - EXTRACT(YEAR FROM started_at)::INTEGER) 
                      else started_at + MAKE_INTERVAL(YEARS := ".($params['yearstart'] + 1)." - EXTRACT(YEAR FROM started_at)::INTEGER) end as started_at,
                    case when id < 5 then ended_at + MAKE_INTERVAL(YEARS := ".$params['yearstart']." - EXTRACT(YEAR FROM ended_at)::INTEGER) 
                      else ended_at + MAKE_INTERVAL(YEARS := ".($params['yearstart'] + 1)." - EXTRACT(YEAR FROM ended_at)::INTEGER) end as ended_at,
                    case when id < 5 then verification_started_at + MAKE_INTERVAL(YEARS := ".$params['yearstart']." - EXTRACT(YEAR FROM verification_started_at)::INTEGER) 
                      else verification_started_at + MAKE_INTERVAL(YEARS := ".($params['yearstart'] + 1)." - EXTRACT(YEAR FROM verification_started_at)::INTEGER) end as verification_started_at,
                    case when id < 5 then verification_ended_at + MAKE_INTERVAL(YEARS := ".$params['yearstart']." - EXTRACT(YEAR FROM verification_ended_at)::INTEGER) 
                      else verification_ended_at + MAKE_INTERVAL(YEARS := ".($params['yearstart'] + 1)." - EXTRACT(YEAR FROM verification_ended_at)::INTEGER) end as verification_ended_at
                from jaga.str_triwulan
                order by triwulan";
            $tw  = $this->rawQuery($query);

            return new CollectionPaginatedResponse([$tbl]);
        }
    }
    // C
    public function copy() {
        // menyalin data dari satu periode ke periode lainnya:
        // untuk keperluan ganti periode baru
        $this->checkScopes(['stranas.admin']);
        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validate( $rawBody, [
            'yearstart' => ['validators' => ['required', 'numeric']],
            'sourceIdPeriode' => ['validators' => ['required', 'numeric']]
        ]);

        // salin semua data yang berkaitan
        $newStrPeriode = $this->copyStrPeriode($params['sourceIdPeriode'], $params['yearstart']);
        $this->copyStrPeriodeTriwulan($newStrPeriode->id, $params['sourceIdPeriode'], $params['yearstart']);
        $this->copyStrTarget($newStrPeriode->id, $params['sourceIdPeriode']);

        return new CollectionPaginatedResponse([$newStrPeriode]);
    }
    private function copyStrPeriode($sourceIdPeriode, $yearstart) {
        // copy jaga.str_periode 
        // $sourceIdPeriode: numeric, contoh: 2
        // $yearstart: numeric, contoh: 2023
        
        // get data from the source
        $sourceStrPeriode = StranasNewPeriode::findFirst($sourceIdPeriode);
        if (empty($sourceStrPeriode)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode tidak ditemukan');
        }
        
        $newStrPeriode = new StranasNewPeriode();
        $newStrPeriode->yearstart = $yearstart;
        $now = date('Y-m-d H:i:s');
        $newStrPeriode->created_at = $now;
        $newStrPeriode->created_by = $this->shared->user->um_id;
        
        foreach (get_object_vars($sourceStrPeriode) as $key => $value) {
            $copiedPropKeys = ['level1', 'level2', 'level3', 'level4',
                'level_count', 'special_month'];
            if (!in_array($key, $copiedPropKeys)) continue;
            $newStrPeriode->$key = $value;
        }

        $newStrPeriode->save();
        return $newStrPeriode;
    }
    // C
    private function copyStrPeriodeTriwulan($newStrPeriodeId, $sourceIdPeriode, $yearstart) {
        // copy jaga.str_periode_triwulan where id_periode = $sourceIdPeriode
        // into jaga.str_periode_triwulan where id_periode = $newStrPeriodeId
        // all corresponding year values shall be translated into $yearstart
        // $newStrPeriodeId: numeric, contoh: 3
        // $sourceIdPeriode: numeric, contoh: 2
        // $yearstart: numeric, contoh: 2023

        // inisiasi
        $sourceStrPeriode = StranasNewPeriode::findFirst($sourceIdPeriode);
        $sourceStrPeriodeTriwulan = $sourceStrPeriode->getDetail();
        $nextyearstart = $yearstart + 1; // tahun kedua

        foreach ($sourceStrPeriodeTriwulan as $row) {
            $newStrPeriodeTriwulan = new StranasNewPeriodeTriwulan();
            $newStrPeriodeTriwulan->id_periode = $newStrPeriodeId;
            
            // copy and process the fields
            $newStrPeriodeTriwulan->id_triwulan = $row['id_triwulan'];
            $newStrPeriodeTriwulan->label = $row['label'];
            foreach ($row as $key => $value) {
                // copy the time values
                $copiedPropKeys = ['started_at', 'ended_at',
                    'verification_started_at', 'verification_ended_at'];
                if (!in_array($key, $copiedPropKeys)) continue;

                // assign the $yearstart or $nextyearstart
                if ($newStrPeriodeTriwulan->id_triwulan < 5) {
                    $time = strval($yearstart).substr($value, 4);
                } else { // for period 5 to 8
                    $time = strval($nextyearstart).substr($value, 4);
                }
                $newStrPeriodeTriwulan->$key = $time;
            }
            $newStrPeriodeTriwulan->save();
        }
    }

    private function copyStrTarget($newStrPeriodeId, $sourceIdPeriode) {
        // copy jaga.str_target where id_periode = $sourceIdPeriode
        // into jaga.str_target where id_periode = $newStrPeriodeId
        // all corresponding values shall be translated
        // condition: only incomplete indicators
        
        // 1. select from jaga.str_target_master, the incomplete only
        $query = "select id, id_target, id_level1, id_level2, id_level3, id_level4, id_instansi
            from jaga.str_target_master
            where id_periode = '$sourceIdPeriode'
            and jaga.latest_verification(nilai_tw8, nilai_tw7, nilai_tw6, nilai_tw5, nilai_tw4, nilai_tw3, nilai_tw2, nilai_tw1) < 100
            order by id_target, id";
        $sourceStrTargetMaster = $this->rawQuery($query);

        // 2. populate jaga.str_target_master
        $id_target = [];
        $strTargetMaster = [];
        foreach($sourceStrTargetMaster as $row){
            if (!in_array($row['id_target'], $id_target)) {
                $id_target[] = $row['id_target']; // populate the id_target
            }
            $strTargetMaster[$row['id_target']][] = $row; // populate based on id_target
        }
        
        // 3. get jaga.str_target
        $strWhere = "id in ({id:array}) and id_periode = '$sourceIdPeriode' and deleted_at is null and NOT is_forced_complete";
        $sourceStrTarget = StranasNewTarget::find([
            $strWhere,
            "bind" => [
                "id" => $id_target
            ],
            "order" => "id"
        ]);

        // 4. get jaga.str_guide
        $strWhere = "id_target in ({id_target:array})";
        $sourceStrTargetGuide = StranasNewTargetGuide::find([
            $strWhere,
            "bind" => [
                "id_target" => $id_target
            ],
            "order" => "id_target"
        ]);

        // 5. populate jaga.str_target_guide
        $strTargetGuide = [];
        foreach($sourceStrTargetGuide as $row){
            $strTargetGuide[$row->id_target][] = $row; // populate based on id_target
        }

        $now = date('Y-m-d H:i:s');

        // 6. save data in new id
        foreach($sourceStrTarget as $row) {
            
            // copy jaga.str_target
            $newStrTarget = new StranasNewTarget();
            $newStrTarget->id_level1 = $row->id_level1;
            $newStrTarget->id_level2 = $row->id_level2;
            $newStrTarget->id_level3 = $row->id_level3;
            $newStrTarget->id_level4 = $row->id_level4;
            $newStrTarget->nama = $row->nama;
            $newStrTarget->info_nilai = $row->info_nilai;
            $newStrTarget->info_lampiran = $row->info_lampiran;
            $newStrTarget->ord = $row->ord;
            $newStrTarget->id_periode = $newStrPeriodeId;
            $newStrTarget->start_triwulan = 1;    
            $newStrTarget->created_at = $now;
            $newStrTarget->created_by = $this->shared->user->um_id;
            $newStrTarget->save();

            // copy jaga.str_target_master
            if (array_key_exists($row->id, $strTargetMaster)) {
                foreach($strTargetMaster[$row->id] as $rowTargetMaster) {
                    $newStrTargetMaster = new StranasNewMasterTarget();
                    $newStrTargetMaster->id_periode = $newStrPeriodeId;
                    $newStrTargetMaster->id_target = $newStrTarget->id;
                    $newStrTargetMaster->id_triwulan = 1;
                    $newStrTargetMaster->id_level1 = $rowTargetMaster['id_level1'];
                    $newStrTargetMaster->id_level2 = $rowTargetMaster['id_level2'];
                    $newStrTargetMaster->id_level3 = $rowTargetMaster['id_level3'];
                    $newStrTargetMaster->id_level4 = $rowTargetMaster['id_level4'];
                    $newStrTargetMaster->id_instansi = $rowTargetMaster['id_instansi'];
                    $newStrTargetMaster->created_at = $now;
                    $newStrTargetMaster->created_by = $this->shared->user->um_id;
                    $newStrTargetMaster->save();
                }
            }

            // copy jaga.str_target_guide
            if (array_key_exists($row->id, $strTargetGuide)) {
                foreach($strTargetGuide[$row->id] as $rowTargetGuide) {
                    $newStrTargetGuide = new StranasNewTargetGuide();
                    $newStrTargetGuide->id_target = $newStrTarget->id;
                    $newStrTargetGuide->aspek = $rowTargetGuide->aspek;
                    $newStrTargetGuide->bobot = $rowTargetGuide->bobot;
                    $newStrTargetGuide->catatan = $rowTargetGuide->catatan;
                    $newStrTargetGuide->ord = $rowTargetGuide->ord;
                    $newStrTargetGuide->save();
                }
            }
        }
    }

    // R
    public function detail($id) {
        $tbl = StranasNewPeriode::findFirst($id);
        if (empty($tbl)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode tidak ditemukan');
        }
        $result = $tbl;
        return new CollectionPaginatedResponse([$result]);
    }
    // U
    public function update($id) {
        $this->checkScopes(['stranas.admin']);
        $tbl = StranasNewPeriode::findFirst($id);

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

        if (!empty($tbl->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode sudah terhapus');
        }

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

        $params = $this->validate( $rawBody, [ 
            'yearstart' => ['validators' => ['required', 'numeric']], 
            'level1' => ['validators' => ['required']], 
            'level2' => ['validators' => ['required']], 
            'level3' => ['validators' => []], 
            'level4' => ['validators' => []], 
            'is_active' => ['validators' => []], 
        ]);

        // validasi
        $tbl->yearstart = $params['yearstart'];
        $tbl->level1 = $params['level1'];
        $tbl->level2 = $params['level2'];
        $tbl->level3 = $params['level3'];
        $tbl->level4 = $params['level4'];
        if(isset($params['is_active'])) {
            $tbl->is_active = $params['is_active'];
        }
        $tbl->level_count = ($params['level4'] != '') ? 4 : 3;

        $now = date('Y-m-d H:i:s');
        $tbl->updated_at = $now;
        $tbl->updated_by = $this->shared->user->um_id;
        $status = $tbl->save();

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

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

            throw new ValidationException($error_messages);
        } else {
            return new CollectionPaginatedResponse([$tbl]);
        }
    }
    // D
    public function delete($id) {
        $this->checkScopes(['stranas.admin']);

        $tbl = StranasNewPeriode::findFirst($id);
        if (empty($tbl)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode tidak ditemukan');
        }
        if (!empty($tbl->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode sudah terhapus');
        }

        $now = date('Y-m-d H:i:s');
        $tbl->deleted_at = $now;
        $tbl->deleted_by = $this->shared->user->um_id;
        $status = $tbl->save();

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

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

            throw new ValidationException($error_messages);
        } else {
            return new CollectionPaginatedResponse([$tbl]);
        }
    }
    // undo delete [butuh ga?]
    public function undo_delete($id) {
        $this->checkScopes(['stranas.admin']);
        $tbl = StranasNewPeriode::findFirst($id);

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

        // validasi
        $tbl->deleted_at = null;
        $tbl->deleted_by = null;
        $status = $tbl->save();

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

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

            throw new ValidationException($error_messages);
        } else {
            return new CollectionPaginatedResponse([$tbl]);
        }
    }
    // ADDITIONAL
    public function toggleActive($id) {
        $this->checkScopes(['stranas.admin']);

        $tbl = StranasNewPeriode::findFirst($id);
        if (empty($tbl)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode tidak ditemukan');
        }
        if (!empty($tbl->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode sudah terhapus');
        }

        // $toggle = !$tbl->is_active;
        $query1 = "update jaga.str_periode set is_active = false";
        $q1  = $this->rawQuery($query1);
        if($q1) {
            $query2 = "update jaga.str_periode set is_active = true where id=".$id;
            $q2  = $this->rawQuery($query2);
        }

        if (!$q2) {
            $errors = $tbl->getMessages();
            $error_messages = [];

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

            throw new ValidationException($error_messages);
        } else {
            $tbl = StranasNewPeriode::findFirst($id);
            return new CollectionPaginatedResponse([$tbl]);
        }
    }

    public function updateTriwulan($id) {
        $this->checkScopes(['stranas.admin']);
        $tbl = StranasNewPeriodeTriwulan::findFirst($id);
        if (empty($tbl)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode tidak ditemukan');
        }

        if (!empty($tbl->deleted_at)) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, 'Periode sudah terhapus');
        }

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

        $params = $this->validate( $rawBody, [ 
            'started_at' => ['validators' => ['required']], 
            'ended_at' => ['validators' => ['required']], 
            'verification_started_at' => ['validators' => ['required']], 
            'verification_ended_at' => ['validators' => ['required']], 
        ]);

        // validasi
        $tbl->started_at = $params['started_at'];
        $tbl->ended_at = $params['ended_at'];
        $tbl->verification_started_at = $params['verification_started_at'];
        $tbl->verification_ended_at = $params['verification_ended_at'];

        $now = date('Y-m-d H:i:s');
        $tbl->updated_at = $now;
        $tbl->updated_by = $this->shared->user->um_id;
        $status = $tbl->save();

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

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

            throw new ValidationException($error_messages);
        } else {
            return new CollectionPaginatedResponse([$tbl]);
        }
    }
}
