<?php

namespace DetailTask;

use KemenkeuClient;
use KemenkeuMasterPemda;
use KemenkeuRealisasiApbd;
use KemenkeuTkdd;
use LogHelper;
use LogKemenkeuErrors;

/**
 * @property KemenkeuClient $client
 */
class KemenkeuTask extends AbstractTask {
    #region Attributes
    private $processedPemda;
    private $processedTkdd;
    private $processedApbd;
    #endregion

    #region Main
    public function init()
    {
        $this->client = new KemenkeuClient($this->config["kemenkeu_config"]);
        $this->client->setLogger($this->logger);
        $this->processedPemda = $this->processedTkdd = $this->processedApbd = 0;
    }

    /**
     * @param $type
     * @return void
     * Logging disimpan ke table log_kemenkeu_errors
     */
    public function process($type) {
        $this->init();
        $this->processName = "Process Kemenkeu Task";
        $startTime = microtime(true);
        if($type == 'daily') {
            $this->processDaily();
        }
        else if ($type == 'monthly') {
            $this->processMonthly();
        }
        LogHelper::logInfo(
            $this->processName,
            $startTime,
            microtime(true),
            [
                ":processed_pemda" => $this->processedPemda,
                ":processed_tkdd" => $this->processedTkdd,
                ":processed_apbd" => $this->processedApbd
            ],
            self::LOG_TYPE,
            $this->logger
        );
    }
    #endregion

    #region Helper
    private function processDaily() {
        $this->processName = "Process Kemenkeu Daily";
        //region Check jika table masih kosong, langsung get data
        //region Pemda
        $countExistingPemda = KemenkeuMasterPemda::count();
        if ($countExistingPemda == 0) {
            $this->getAndSaveAllDataPemda();
        }
        //endregion

        //region TKDD
        $countExistingTkdd = KemenkeuTkdd::count();
        if ($countExistingTkdd == 0) {
            $this->getAndSaveAllDataTkdd();
        }
        //endregion

        //region APBD
        $countExistingApbd = KemenkeuRealisasiApbd::count();
        if ($countExistingApbd == 0) {
            $this->getAndSaveAllDataApbd();
        }
        //endregion
        //endregion

        //region Check Log Error, jika ada, lakukan pengambilan data ulang, jika berhasil, hapus
        //region Pemda
        $isPemdaError = LogKemenkeuErrors::count([
                'conditions' => 'type = :type:',
                'bind' => [
                    'type' => "PEMD"
                ]
            ]) > 0;
        if ($isPemdaError) {
            try {
                $this->getAndSaveAllDataPemda();
                $errorLog = LogKemenkeuErrors::findFirst([
                    'conditions' => ' type = :type:',
                    'bind' => [
                        'type' => 'PEMD'
                    ]
                ]);
                $errorLog->delete();
            } catch (\Exception $e) {
                //DO NOTHING, karena error masih tercatat dan belum terhapus
            }
        }
        //endregion

        //region TKDD
        $errorTkdd = LogKemenkeuErrors::find([
            'conditions' => 'type = :type:',
            'bind' => [
                'type' => "TKDD"
            ]
        ]);
        if(!empty($errorTkdd)) {
            foreach ($errorTkdd as $itemError) {
                if($itemError->range == 'ALL') {
                    $this->getAndSaveAllDataTkdd();
                    $errorTkdd[0]->delete();
                }
                else {
                    try {
                        $this->client->requestTokenTkdd();
                        $dataTkdd = $this->client->getTransaksiTkdd($itemError->range);
                        foreach ($dataTkdd as $itemTkdd) {
                            $this->client->saveDataTkdd($itemTkdd);
                        }
                        $itemError->delete();
                    }
                    catch (\Exception $e) {
                        //DO NOTHING
                    }
                }
            }
        }
        //endregion

        //region APBD
        $errorApbd = LogKemenkeuErrors::find([
            'conditions' => 'type = :type:',
            'bind' => [
                'type' => "APBD"
            ]
        ]);
        if(!empty($errorApbd)) {
            foreach ($errorApbd as $itemError) {
                if($itemError->range == 'ALL') {
                    $this->getAndSaveAllDataApbd();
                    $errorApbd[0]->delete();
                }
                else {
                    try {
                        $this->client->requestTokenRealisasiApbd();
                        $dataApbd = $this->client->getRealisasiApbd($itemError->range);
                        foreach ($dataApbd as $itemApbd) {
                            $this->client->saveDataApbd($itemApbd);
                        }
                        $itemError->delete();
                    }
                    catch (\Exception $e) {
                        //DO NOTHING
                    }
                }
            }
        }
        //endregion
        //endregion
    }

    private function processMonthly() {
        $this->processName = "Process Kemenkeu Monthly";
        //region Get data Referensi Pemda
        $countExistingPemda = KemenkeuMasterPemda::count();
        $isPemdaError = false;
        if ($countExistingPemda > 0) {
            $isPemdaError = LogKemenkeuErrors::count([
                    'conditions' => 'type = :type:',
                    'bind' => [
                        'type' => "PEMD"
                    ]
                ]) > 0;
        }
        if ($countExistingPemda == 0 || $isPemdaError) {
            try {
                $this->getAndSaveAllDataPemda();
                if ($isPemdaError) {
                    $errorLog = LogKemenkeuErrors::findFirst([
                        'conditions' => ' type = :type:',
                        'bind' => [
                            'type' => 'PEMD'
                        ]
                    ]);
                    $errorLog->delete();
                }
            } catch (\Exception $e) {
                //NOTE: Jika sebelumnya tidak error, maka catat, jika sebelumnya error, tidak perlu dicatat lagi
                if(!$isPemdaError) {
                    $errorLog = new LogKemenkeuErrors();
                    $errorLog->type = 'PEMD';
                    $errorLog->range = 'ALL';
                    $errorLog->save();
                }
            }
        }
        //endregion

        //region Get Data TKDD
        $this->getAndSaveAllDataTkdd();
        //endregion

        //region Get Data Realisasi APBD
        $this->getAndSaveAllDataApbd();
        //endregion
    }

    private function updateKodeKemendagriKemenkeuPemda() {
        $qUpdateProvinsiCode = "UPDATE jaga.kemenkeu_master_pemda SET kodeprovinsi = provinsi.provinsi_code FROM (SELECT provinsi_code, provinsi_name FROM master_provinsi) AS provinsi WHERE namapemda ILIKE 'Provinsi %' AND provinsi.provinsi_name ILIKE CONCAT('%', REPLACE(REPLACE(REPLACE(namapemda, 'Kab. ', ''), 'Kota ', ''), 'Provinsi ', ''), '%');";
        $qUpdateKabKotaCode = "
                    UPDATE jaga.kemenkeu_master_pemda SET kodeprovinsi = kabkota.provinsi_code, kodekabkota = kabkota.kota_kabupaten_code FROM (SELECT provinsi_code, kota_kabupaten_code, kota_Kabupaten_name FROM master_kota_kabupaten) AS kabkota WHERE 
                    ((namapemda ILIKE 'Kota %')  AND kabkota.kota_Kabupaten_name ILIKE CONCAT('%', namapemda))
                    OR ((namapemda ILIKE 'Kab. %'OR namapemda ILIKE 'Kab %')  AND kabkota.kota_Kabupaten_name ILIKE REPLACE(REPLACE(namapemda, 'Kab. ', ''), 'Kab ', ''))
                    OR ((namapemda ILIKE 'Kab. %'OR namapemda ILIKE 'Kab %')  AND REPLACE(kabkota.kota_Kabupaten_name, ' ', '') ILIKE REPLACE(REPLACE(REPLACE(namapemda, 'Kab. ', ''), 'Kab ', ''), ' ', ''))
                    OR (namapemda ILIKE 'Kab. Muaro Jambi' AND kabkota.kota_kabupaten_name ILIKE 'MUAROJAMBI')
                    OR (namapemda ILIKE 'Kota Bukit Tinggi' AND kabkota.kota_kabupaten_name ILIKE 'KOTA BUKITTINGGI')
                    OR (namapemda ILIKE 'Kab. Toli-Toli' AND kabkota.kota_kabupaten_name ILIKE 'TOLI TOLI')
                    OR (namapemda ILIKE 'Kota Padang Sidempuan' AND kabkota.kota_kabupaten_name ILIKE 'KOTA PADANGSIDIMPUAN')
                    OR (namapemda ILIKE 'Kab. Limapuluh Kota' AND kabkota.kota_kabupaten_name ILIKE 'LIMA PULUH KOTA')
                    OR (namapemda ILIKE 'Kota Pematang Siantar' AND kabkota.kota_kabupaten_name ILIKE 'KOTA PEMATANGSIANTAR')
                    OR (namapemda ILIKE 'Kota Pare-pare' AND kabkota.kota_kabupaten_name ILIKE 'KOTA PARE PARE')
                    OR (namapemda ILIKE 'Kab. Pohuwato' AND kabkota.kota_kabupaten_name ILIKE 'PAHUWATO')
                    OR (namapemda ILIKE 'Kab. Mukomuko' AND kabkota.kota_kabupaten_name ILIKE 'MUKO MUKO')
                    OR (namapemda ILIKE 'Kab. OKU Selatan' AND kabkota.kota_kabupaten_name ILIKE 'OGAN KOMERING ULU SELATAN')
                    OR (namapemda ILIKE 'Kab. OKU Timur' AND kabkota.kota_kabupaten_name ILIKE 'OGAN KOMERING ULU TIMUR')
                    OR (namapemda ILIKE 'Kota Baubau' AND kabkota.kota_kabupaten_name ILIKE 'KOTA BAU BAU')
                    OR (namapemda ILIKE 'Kab. Kepulauan Tanimbar' AND kabkota.kota_kabupaten_name ILIKE 'MALUKU TENGGARA BARAT')
                    OR (namapemda ILIKE 'Kab. Timor Tengah Selatan' AND kabkota.kota_kabupaten_name ILIKE 'KAB TIMOR TENGAH SELATAN')
                    OR (namapemda ILIKE 'Kab. Sangihe' AND kabkota.kota_kabupaten_name ILIKE 'KEPULAUAN SANGIHE')
                    OR (namapemda ILIKE 'Kab. Pegunungan Bintang' AND kabkota.kota_kabupaten_name ILIKE 'KAB PEGUNUNGAN BINTANG')
                    ;
                ";
        $this->rawQuery($qUpdateProvinsiCode);
        $this->rawQuery($qUpdateKabKotaCode);
    }

    private function getAndSaveAllDataPemda() {
        try {
            $this->client->requestTokenReferensiPemda();
            $dataPemda = $this->client->getReferensiPemda();
            foreach ($dataPemda as $itemPemda) {
                $this->client->saveDataPemda($itemPemda);
                $this->processedPemda++;
            }
            $this->updateKodeKemendagriKemenkeuPemda();
        } catch (\Exception $e) {
            $countLog = LogKemenkeuErrors::count([
                'conditions' => 'type = :type: AND range = :range:',
                'bind' => [
                    'type' => 'PEMD',
                    'range' => 'ALL'
                ]
            ]);
            if($countLog == 0) {
                $errorLog = new LogKemenkeuErrors();
                $errorLog->type = 'PEMD';
                $errorLog->range = 'ALL';
                $errorLog->save();
            }
        }
    }

    private function getAndSaveAllDataTkdd() {
        $totalData = 0;
        try {
            $this->client->requestTokenTkdd();
            $headers = $this->client->getTransaksiTkddHeaders();
            $totalData = explode('/', $headers['Content-Range'][0])[1];
        } catch (\Exception $e) {
            //Failed to get all
            $countLog = LogKemenkeuErrors::count([
                'conditions' => 'type = :type: AND range = :range:',
                'bind' => [
                    'type' => 'TKDD',
                    'range' => 'ALL'
                ]
            ]);
            if($countLog == 0) {
                $errorLog = new LogKemenkeuErrors();
                $errorLog->type = 'TKDD';
                $errorLog->range = 'ALL';
                $errorLog->save();
            }
        }

        $i = 0;
        while ($i < $totalData) {
            if ($i % 100000) $this->client->requestTokenTkdd();
            $batasAtas = $i;
            try {
                $batasAtas = min(($i + 9999), ($totalData - 1));
                $dataTkdd = $this->client->getTransaksiTkdd($i . '-' . $batasAtas);
                foreach ($dataTkdd as $itemTkdd) {
                    $this->client->saveDataTkdd($itemTkdd);
                    $this->processedTkdd++;
                }
            } catch (\Exception $e) {
                $errorLog = new LogKemenkeuErrors();
                $errorLog->type = 'TKDD';
                $errorLog->range = $i . '-' . $batasAtas;
                $errorLog->save();
            }
            $i = $batasAtas + 1;
        }
    }

    private function getAndSaveAllDataApbd() {
        $totalData = 0;
        try {
            $this->client->requestTokenRealisasiApbd();
            $headers = $this->client->getRealisasiApbdHeaders();
            $totalData = explode('/', $headers['Content-Range'][0])[1];
        } catch (\Exception $e) {
            //Failed to get all
            $countLog = LogKemenkeuErrors::count([
                'conditions' => 'type = :type: AND range = :range:',
                'bind' => [
                    'type' => 'APBD',
                    'range' => 'ALL'
                ]
            ]);
            if($countLog == 0) {
                $errorLog = new LogKemenkeuErrors();
                $errorLog->type = 'APBD';
                $errorLog->range = 'ALL';
                $errorLog->save();
            }
        }

        $i = 0;
        while ($i < $totalData) {
            if ($i % 100000) $this->client->requestTokenRealisasiApbd();
            $batasAtas = $i;
            try {
                $batasAtas = min(($i + 9999), ($totalData - 1));
                $dataApbd = $this->client->getRealisasiApbd($i . '-' . $batasAtas);
                foreach ($dataApbd as $itemApbd) {
                    $this->client->saveDataApbd($itemApbd);
                    $this->processedApbd++;
                }
            } catch (\Exception $e) {
                $errorLog = new LogKemenkeuErrors();
                $errorLog->type = 'APBD';
                $errorLog->range = $i . '-' . $batasAtas;
                $errorLog->save();
            }
            $i = $batasAtas + 1;
        }
    }
    #endregion
}
