<?php

namespace DetailTask;

use AppConfig;
use DesaClient;
use LogHelper;
use OmspanMasterPemda;
use OmspanMasterProvinsi;

/**
 * @property DesaClient $client
 */
class OmspanDesaTask extends AbstractTask {
    #region Attributes
    private $activeYears;
    private $paguYears;
    /**
     * @var DesaClient
     */
    private $totalProvinsi;
    private $provinsis;
    private $kabKotas;
    private $periodeAwal;
    private $periodeAkhir;
    #endregion

    #region Main
    public function init() {
        $activeYears = AppConfig::getValueByKode('OMSPAN_YEARS');
        if ($activeYears) {
            $activeYears = explode(";", $activeYears);
        }
        $this->activeYears = $activeYears;
        $this->client = new DesaClient($this->config["desa_prop"]);
        $this->client->setLogger($this->logger);
    }

    /**
     * @param integer $type (0 = Pagu, >0 = offset Provinsi Penyerapan/Penyaluran)
     * @return void
     * Logging disimpan ke file log
     */
    public function processDanaDesa(int $type) {
        $this->init();
        if ($type == 0) {
            $this->processPagu();
        } else {
            $this->processPenyaluranPenyerapan($type);
        }
    }
    #endregion

    #region Pagu
    private function processPagu() {
        $startTime = microtime(true);
        $this->processPaguForAllYears();
        $endTime = microtime(true);
        LogHelper::logInfo("Process Omspan Pagu Dana Desa", $startTime, $endTime, [], self::LOG_TYPE, $this->logger);
    }

    private function processPaguByActiveYears() {
        for ($year = 2018; $year <= date("Y"); $year++) {
            if (in_array($year, $this->activeYears)) {
                $this->processPaguForYear($year);
            }
        }
    }

    private function processPaguByStatusDesa() {
        for ($year = 2021; $year <= date("Y"); $year++) {
            $totalRows = \OmspanDanaDesaPagu::query()
                ->columns("count(*) as total")
                ->where("tahun = :tahun:")
                ->bind(["tahun" => $year])
                ->execute()[0]["total"];
            $totalRowsCompleted = \OmspanDanaDesaPagu::query()
                ->columns("count(*) as total")
                ->where("tahun = :tahun: and status_desa is not null")
                ->bind(["tahun" => $year])
                ->execute()[0]["total"];
            if ($totalRows !== $totalRowsCompleted) {
                $this->processPaguForYear($year);
                //print_r("Pagu tahun " . $year . " belum sesuai. Total rows: " . $totalRows . ". Total kosong: " . ($totalRows - $totalRowsCompleted) . "\n");
            } else {
                //print_r("Pagu tahun " . $year . " telah sesuai. Total rows: " . $totalRows . "\n");
            }
        }
    }

    private function processPaguForAllYears() {
        $this->paguYears = [];
        $omspanPaguYears = AppConfig::getValueByKode("OMSPAN_PAGU_YEARS");
        $this->paguYears = explode(";", $omspanPaguYears);
        foreach ($this->paguYears as $year) {
            if (!empty($year) && is_numeric($year)) {
                $this->processPaguForYear($year);
            }
        }
    }

    private function processPaguForYear($year) {
        try {
            $this->processName = 'Process Omspan Pagu Dana Desa ' . $year;
            $this->client->danaPaguDesa($year);
            $this->logInfo();
        } catch (\Exception $e) {
            $this->handleException($e);
        }
    }
    #endregion

    #regionPenyaluran-Penyerapan
    public function processPenyaluranPenyerapan($offset) {
        $startTime = microtime(true);
        $this->setTotalProvinsi();
        if ($offset <= $this->totalProvinsi) {
            $this->setProvinsis($offset);
            foreach ($this->provinsis as $provinsi) {
                $this->setKabKotas($provinsi['kd_prov']);
                for ($year = 2018; $year <= date('Y'); $year++) {
                    if (in_array($year, $this->activeYears)) {
                        $this->setPeriodePenyaluranForYear($year);
                        foreach ($this->kabKotas as $kabKota) {
                            $kdProv = $kabKota['kd_prov'];
                            $kdKab = $kabKota['kd_lokasi'];
                            $this->processPenyaluranForYear($year, $kdProv, $kdKab);
                            $this->processPenyerapanForYear($year, $kdProv, $kdKab);
                        }
                    }
                }
            }
        }
        $endTime = microtime(true);
        LogHelper::logInfo("Process Omspan Penyaluran Penyerapan Dana Desa", $startTime, $endTime, [], self::LOG_TYPE, $this->logger);
    }

    private function processPenyaluranForYear($year, $kdProv, $kdKab) {
        $this->processName = 'Process Omspan Penyaluran Dana Desa ' . $year;
        try {
            $this->client->penyaluranDanaDesa($year, $this->periodeAwal, $this->periodeAkhir, $kdProv, $kdKab);
            $this->logInfo([
                "_periode_awal" => $this->periodeAwal,
                "_periode_akhir" => $this->periodeAkhir,
                "_kd_prov" => $kdProv,
                "_kd_kab" => $kdKab
            ]);
        } catch (\Exception $e) {
            $this->handleException($e);
        }
    }

    private function processPenyerapanForYear($year, $kdProv, $kdKab) {
        $this->processName = 'Process Omspan Penyerapan Dana Desa ' . $year;
        try {
            $this->client->penyerapanDanaDesa($year, $kdProv, $kdKab);
            $this->logInfo([
                "_kd_prov" => $kdProv,
                "_kd_kab" => $kdKab
            ]);
        } catch (\Exception $e) {
            $this->handleException($e);
        }
    }
    #endregion

    #region Helper

    private function setTotalProvinsi() {
        $this->totalProvinsi = OmspanMasterProvinsi::find()->count();
    }
    private function setProvinsis($offset) {
        $batch = ceil($offset / 10);

        $dbOffset = ($batch - 1) * 10;

        $this->provinsis = OmspanMasterProvinsi::find([
            'limit' => 10,
            'offset' => $dbOffset,
            'order' => 'kd_prov'
        ])->toArray();
    }

    private function setKabKotas($kdProv) {
        $this->kabKotas = OmspanMasterPemda::find([
            'conditions' => 'kd_prov = :kd_prov:',
            'bind' => ['kd_prov' => $kdProv],
            'order' => 'kd_lokasi'
        ])->toArray();
    }

    private function setPeriodePenyaluranForYear($year) {
        switch ($year) {
            case 2021:
                $this->periodeAwal = AppConfig::getValueByKode("OMSPAN_PENYALURAN_START_PERIOD_2021");
                $this->periodeAkhir = AppConfig::getValueByKode("OMSPAN_PENYALURAN_LAST_PERIOD_2021");
                break;
            case 2022:
                $this->periodeAwal = AppConfig::getValueByKode("OMSPAN_PENYALURAN_START_PERIOD_2022");
                $this->periodeAkhir = AppConfig::getValueByKode("OMSPAN_PENYALURAN_LAST_PERIOD_2022");
                break;
            case 2023:
                $this->periodeAwal = AppConfig::getValueByKode("OMSPAN_PENYALURAN_START_PERIOD_2023");
                $this->periodeAkhir = "12";
                break;
            case intval(date("Y")):
                $this->periodeAwal = "01";
                $this->periodeAkhir = date("m");
                break;
            default:
                $this->periodeAwal = "01";
                $this->periodeAkhir = "12";
                break;
        }
    }

    private function logInfo($additionalData = array()) {
        $additionalData = array_merge(
            $additionalData,
            [
                "objects_processed" => $this->client->getObjectsProcessed()
            ]
        );
        LogHelper::logInfo(
            $this->processName,
            $this->client->getStartTime(),
            $this->client->getEndTime(),
            $additionalData,
            self::LOG_TYPE,
            $this->logger
        );
    }

    private function handleException($e) {
        $this->logger->addItem("message", $this->processName);
        $this->logger->addItem("type_of_log", "scheduled_job_exception");
        $this->logger->addItem("error_message", $e->getMessage());
        $this->logger->error();
    }
    #endregion
}
