<?php

class PpjClient extends BackgroundBaseClient {
    private function getHeader() {
        return [
            "Authorization" => "Basic " . base64_encode($this->prop["username"] . ':' . $this->prop["password"])
        ];
    }

    public function getLapPpjHal1($in_kd_kab, $in_thbl)
    {
        $method = "POST";
        $path = "/api/ap2tkpk/getlapppjhal1";
        $params = [
            "query" => [
                "in_kd_kab" => $in_kd_kab,
                "in_thbl" => $in_thbl
            ],
            "headers" => $this->getHeader()
        ];

        //region LOG Definition
        $this->setApiName("PPJ-get-lap-ppj-hal-1");
        //endregion

        return $this->execute($method, $path, $params, false);
    }

    public function getLapPpjHal2($in_kd_kab, $in_thbl)
    {
        $method = "POST";
        $path = "/api/ap2tkpk/getlapppjhal2";
        $params = [
            "query" => [
                "in_kd_kab" => $in_kd_kab,
                "in_thbl" => $in_thbl
            ],
            "headers" => $this->getHeader()
        ];

        //region LOG Definition
        $this->setApiName("PPJ-get-lap-ppj-hal-2");
        //endregion

        return $this->execute($method, $path, $params, false);
    }

    public function getPiutangPemda($in_kd_kab, $in_thbl)
    {
        $method = "POST";
        $path = "/api/ap2tkpk/getpiutangpemda";
        $params = [
            "query" => [
                "in_kd_kab" => $in_kd_kab,
                "in_thbl" => $in_thbl
            ],
            "headers" => $this->getHeader()
        ];

        //region LOG Definition
        $this->setApiName("PPJ-get-piutang-pemda");
        //endregion

        return $this->execute($method, $path, $params, false);
    }

    // isi param $period utk mengambil data pada periode tertentu
    // kosongkan utk mengambil periode -1 bulan berjalan
    public function updateMonthly($period = null) {
        $this->startTime = microtime(true);
        if (!$period) {
            // set periode = bulan berjalan - 1 bulan
            $period = date("Ym", strtotime( date( "Y-m-d", strtotime( date("Y-m-d") ) ) . "-1 month" ) );
        }

        // ambil referensi instansi pemda tingkat 2
        $kabKotas = Instansi::find([
            'conditions' => "id_tipe = 2 AND deleted_at IS NULL",
            'columns' => 'DISTINCT(id_kota_kabupaten) as id_kota_kabupaten, nama'
        ]);

        // data cleansing
        $q = [
            'conditions' => "thbllap = :period:",
            'bind' => [
                'period' => $period
            ]
        ];
        PpjHal1::find($q)->delete();
        PpjHal2::find($q)->delete();
        PpjPiutangPemda::find($q)->delete();

        $objectsProcessed = 0;
        // loop referensi kota kabupaten
        foreach ($kabKotas as $kabKota) {
            $objectsProcessed+= $this->processPpj($kabKota['id_kota_kabupaten'], $kabKota['nama'], $period);
        }
        $this->objectsProcessed = $objectsProcessed;
        $this->endTime = microtime(true);
    }

    public function updateDaily()
    {
        $this->startTime = microtime(true);
        $logs = LogPpjErrors::find([
            'conditions' => 'deleted_at is null and retry_count <= :a:',
            'bind' => ['a' => AppConfig::getValueByKode("MAX_RETRY_ERROR_PPJ")]
        ]);

        $objectsProcessed = 0;
        foreach ($logs as $log) {
            /** @var $log LogPpjErrors */
            $q = [
                'conditions' => "thbllap = :period: AND kd_kabmendagri = :kd_kabmendagri:",
                'bind' => [
                    'period' => $log->periode,
                    'kd_kabmendagri' => $log->kabupaten_kota_code
                ]
            ];
            if ($log->halaman == 1) {
                PpjHal1::find($q)->delete();
                $objectsProcessed+= $this->processPpjHal1($log->kabupaten_kota_code, $log->instansi, $log->periode);
            } elseif ($log->halaman == 2) {
                PpjHal2::find($q)->delete();
                $objectsProcessed+= $this->processPpjHal2($log->kabupaten_kota_code, $log->instansi, $log->periode);
            } elseif ($log->halaman == 3) {
                PpjPiutangPemda::find($q)->delete();
                $objectsProcessed+= $this->processPpjPiutangPemda($log->kabupaten_kota_code, $log->instansi, $log->periode);
            }
        }
        $this->objectsProcessed = $objectsProcessed;
        $this->endTime = microtime(true);
    }

    private function processPpj($kodePemda, $namaPemda, $period) {
        return $this->processPpjHal1($kodePemda, $namaPemda, $period)
            + $this->processPpjHal2($kodePemda, $namaPemda, $period)
            + $this->processPpjPiutangPemda($kodePemda, $namaPemda, $period);
    }

    private function processPpjHal1($kodePemda, $namaPemda, $period)
    {
        $objectsProcessed = 0;
        try {
            $maxRetry = 3;
            $attempt = 0;
            $ppjhal1 = null;
            $lastError = null;

            while ($attempt < $maxRetry) {
                $attempt++;
                try {
                    $ppjhal1 = $this->getLapPpjHal1($kodePemda, $period);

                    $isValid =
                        is_array($ppjhal1) &&
                        array_key_exists('rc', $ppjhal1) && $ppjhal1['rc'] === '00' &&
                        array_key_exists('data', $ppjhal1) && is_array($ppjhal1['data']);

                    if ($isValid) {
                        $lastError = null;
                        break;
                    }

                    $lastError = "Not expected response getLapPpjHal1 (attempt {$attempt}/{$maxRetry}): " . json_encode($ppjhal1);
                } catch (\Exception $ex) {
                    $lastError = "Exception thrown getLapPpjHal1 (attempt {$attempt}/{$maxRetry}): " . $ex->getMessage();
                }

                if ($attempt < $maxRetry) {
                    usleep(300000); // 300ms
                }
            }

            if ($lastError === null) {
                $data = $ppjhal1['data'];
                $objectsProcessed = sizeof($data);

                foreach ($data as $datum) {
                    $model = new PpjHal1();
                    $model->assign($datum);
                    $model->created_at = DateHelper::getNowTimezoned();
                    $model->updated_at = DateHelper::getNowTimezoned();
                    $model->save();
                }

                LogPpjErrors::clearWithData($kodePemda, $period, 1);
            } else {
                LogPpjErrors::saveWithData($kodePemda, $namaPemda, $period, 1, $lastError);
            }
        } catch (\Exception $e) {
            LogPpjErrors::saveWithData($kodePemda, $namaPemda, $period, 1, "Exception thrown processing getLapPpjHal1: " . $e->getMessage());
        }

        return $objectsProcessed;
    }

    private function processPpjHal2($kodePemda, $namaPemda, $period)
    {
        $objectsProcessed = 0;

        try {
            $maxRetry = 3;
            $attempt = 0;
            $ppjhal2 = null;
            $lastError = null;

            while ($attempt < $maxRetry) {
                $attempt++;
                try {
                    $ppjhal2 = $this->getLapPpjHal2($kodePemda, $period);

                    $isValid =
                        is_array($ppjhal2) &&
                        array_key_exists('rc', $ppjhal2) && $ppjhal2['rc'] === '00' &&
                        array_key_exists('data', $ppjhal2) && is_array($ppjhal2['data']);

                    if ($isValid) {
                        $lastError = null;
                        break;
                    }

                    $lastError = "Not expected response getLapPpjHal2 (attempt {$attempt}/{$maxRetry}): " . json_encode($ppjhal2);
                } catch (\Exception $ex) {
                    $lastError = "Exception thrown getLapPpjHal2 (attempt {$attempt}/{$maxRetry}): " . $ex->getMessage();
                }

                if ($attempt < $maxRetry) {
                    usleep(300000); // 300ms
                }
            }

            if ($lastError === null) {
                $data = $ppjhal2['data'];
                $objectsProcessed = sizeof($data);

                foreach ($data as $datum) {
                    $model = new PpjHal2();
                    $model->assign($datum);
                    $model->created_at = DateHelper::getNowTimezoned();
                    $model->updated_at = DateHelper::getNowTimezoned();
                    $model->save();
                }

                LogPpjErrors::clearWithData($kodePemda, $period, 2);
            } else {
                LogPpjErrors::saveWithData($kodePemda, $namaPemda, $period, 2, $lastError);
            }
        } catch (\Exception $e) {
            LogPpjErrors::saveWithData(
                $kodePemda,
                $namaPemda,
                $period,
                2,
                "Exception thrown processing getLapPpjHal2: " . $e->getMessage()
            );
        }

        return $objectsProcessed;
    }

    private function processPpjPiutangPemda($kodePemda, $namaPemda, $period)
    {
        $objectsProcessed = 0;

        try {
            $maxRetry = 3;
            $attempt = 0;
            $ppjpiutangpemda = null;
            $lastError = null;

            while ($attempt < $maxRetry) {
                $attempt++;
                try {
                    $ppjpiutangpemda = $this->getPiutangPemda($kodePemda, $period);

                    $isValid =
                        is_array($ppjpiutangpemda) &&
                        array_key_exists('rc', $ppjpiutangpemda) && $ppjpiutangpemda['rc'] === '00' &&
                        array_key_exists('data', $ppjpiutangpemda) && is_array($ppjpiutangpemda['data']);

                    if ($isValid) {
                        $lastError = null;
                        break;
                    }

                    $lastError = "Not expected response getPiutangPemda (attempt {$attempt}/{$maxRetry}): " . json_encode($ppjpiutangpemda);
                } catch (\Exception $ex) {
                    $lastError = "Exception thrown getPiutangPemda (attempt {$attempt}/{$maxRetry}): " . $ex->getMessage();
                }

                if ($attempt < $maxRetry) {
                    usleep(300000); // 300ms
                }
            }

            if ($lastError === null) {
                $data = $ppjpiutangpemda['data'];
                $objectsProcessed = sizeof($data);

                foreach ($data as $datum) {
                    $model = new PpjPiutangPemda();
                    $model->assign($datum);
                    $model->created_at = DateHelper::getNowTimezoned();
                    $model->updated_at = DateHelper::getNowTimezoned();
                    $model->save();
                }

                LogPpjErrors::clearWithData($kodePemda, $period, 3);
            } else {
                LogPpjErrors::saveWithData($kodePemda, $namaPemda, $period, 3, $lastError);
            }
        } catch (\Exception $e) {
            LogPpjErrors::saveWithData(
                $kodePemda,
                $namaPemda,
                $period,
                3,
                "Exception thrown processing getPiutangPemda: " . $e->getMessage()
            );
        }

        return $objectsProcessed;
    }
}
