<?php

class BpjsController extends BaseController
{
    public function detail()
    {
        $this->checkIsAuthenticated();

        $params = $this->validate(
            $this->request->get(),
            [
                "nik" => ['validators' => ['required', 'digit']],
                "tgl_lahir" => ['validators' => ['required', 'date']],
                "captcha_uuid" => ['validators' => ['required']],
                "captcha_answer" => ['validators' => ['required']]
            ]
        );

        $captchas = Captcha::find([
            'conditions' => 'uuid = :uuid:',
            'bind' => [
                'uuid' => $params['captcha_uuid']
            ]
        ]);

        if (empty($captchas) || count($captchas) < 1) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Captcha not found");
        }

        $captcha = $captchas[0];

        if ($captcha->isUsed()) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Captcha already used");
        }

        if ($captcha->isExpired()) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Captcha expired");
        }

        if (!$captcha->match($params['captcha_answer'])) {
            throw new CustomErrorException(BaseResponse::INVALID_REQUEST, "Captcha doesn't match");
        }

        $captcha->markUsed();

        $bpjsClient = new Bpjs2Client($this->config['bpjs2_config']);

        //region Set Logger from DI to Client
        $bpjsClient->setLogger($this->logger);
        //endregion

        $result = null;
        try {
            $result = $bpjsClient->getDetailByNIKAndTglLahir($params['nik'], $params['tgl_lahir']);
        } catch (\Exception $ex) {
            throw new CustomErrorException(BaseResponse::UNEXPECTED_ERROR, "Terjadi kesalahan. Mohon periksa kembali data peserta dengan NIK dan tanggal lahir.");
        }

        return new SimpleResponse($result);
    }

    public function getListKabKota() {
        $reqParam = $this->request->get();
        $this->checkIsAuthenticated();
        $conditions = [];
        $bind = [];

        if(array_key_exists('namadati2', $reqParam)) {
            array_push($conditions, 'namadati2 ilike :namadati2:');
            $bind['namadati2'] = '%' . $reqParam['namadati2'] . '%';
        }

        $findParams = [
            'columns' => 'kodedati2, namadati2',
            'group' => 'kodedati2, namadati2'
        ];

        if(count($conditions) > 0) {
            $findParams['conditions'] = implode(' AND ', $conditions);
            $findParams['bind'] = $bind;
        }

        $listKabKota = BpjsKotaKabupaten::find($findParams);
        $totalRecords = $listKabKota->count();
        return new PaginatedResponse($listKabKota, $totalRecords, $totalRecords, 0);
    }

    public function getListPuskesmas() {
        $this->checkIsAuthenticated();

        $params = $this->request->get();

        $params['limit'] = $this->getDefaultLimit($params);
        $params['offset'] = array_key_exists('offset', $params) ? $params['offset'] : 0;
        $params['namapuskesmas'] = array_key_exists('namapuskesmas', $params) ? $params['namapuskesmas'] : "";
        $params['kodedati2'] = array_key_exists('kodedati2', $params) ? $params['kodedati2'] : "";
        $params['order_by'] = array_key_exists('order_by', $params) ? $params['order_by'] : "namapuskesmas";
        $params['order_direction'] = array_key_exists('order_direction', $params) ? $params['order_direction'] : "asc";

        $allowedOrder = ['namapuskesmas'];
        $allowedDirection = ['asc', 'desc'];

        $validatedRequest = $this->validate(
            $params,
            [
                'limit' => ['validators' => ['digit']],
                'offset' => ['validators' => ['digit']],
                'order_by' => ['validators' => [
                    [
                        'name' => 'inclusion_in',
                        'params' => $allowedOrder
                    ]
                ]],
                'order_direction' => ['validators' => [
                    [
                        'name' => 'inclusion_in',
                        'params' => $allowedDirection
                    ]
                ]],
            ]
        );

        if(!empty($params['kodedati2'])) {
            $dati2Data = BpjsKotaKabupaten::find([
                'conditions' => '(puskesmas_last_update_at IS NULL OR puskesmas_last_update_at <= ?0 OR puskesmas_last_update_page <> ?1 OR puskesmas_last_update_page IS NULL) AND kodedati2 = ?2',
                'bind' => [
                    date('Y-m-d', strtotime('-7 day')),
                    'LAST',
                    $params['kodedati2']
                ]
            ]);
            if($dati2Data->count() > 0) {
                try {
                    $bpjs2Client = new Bpjs2Client($this->config['bpjs2_config']);
                    $bpjs2Client->setLogger($this->logger);
                    $updatePuskesmas = [];
                    $lastPage = ($dati2Data[0]->puskesmas_last_update_page == 'LAST' || $dati2Data[0]->puskesmas_last_update_page == null) ? 1 : $dati2Data[0]->puskesmas_last_update_page;

                    $respProfilPuskesmas = $bpjs2Client->getProfilPuskesmas(1, $params['kodedati2']);
                    if (!$bpjs2Client->isBpjsResponseTimeout($respProfilPuskesmas)) {
                        if (array_key_exists('metaData', $respProfilPuskesmas)) {
                            if ($respProfilPuskesmas['metaData']['code'] == '200') {
                                $totalRecords = $respProfilPuskesmas['response']['count'];
                                $totalPage = ceil($totalRecords / 10);
                                $lastPage++;

                                $updatePuskesmas = array_merge($updatePuskesmas, $respProfilPuskesmas['response']['list']);
                                for ($page = $lastPage; $page <= $totalPage; $page++) {
                                    $lastPage = $page;
                                    $respProfilPuskesmas = $bpjs2Client->getProfilPuskesmas($page, $params['kodedati2']);
                                    if ($bpjs2Client->isBpjsResponseTimeout($respProfilPuskesmas)) break;

                                    if (array_key_exists('metaData', $respProfilPuskesmas)) {
                                        if ($respProfilPuskesmas['metaData']['code'] == '200') {
                                            $updatePuskesmas = array_merge($updatePuskesmas, $respProfilPuskesmas['response']['list']);
                                        }
                                    }
                                }
                                if ($lastPage >= $totalPage) $lastPage = 'LAST';
                            }
                        }
                    }

                    if (count($updatePuskesmas) > 0) {
                        $kabupatens = BpjsKotaKabupaten::find([
                            'conditions' => 'kodedati2 = ?0',
                            'bind' => [
                                $params['kodedati2']
                            ]
                        ]);
                        foreach ($kabupatens as $item) {
                            $item->puskesmas_last_update_at = date('Y-m-d H:i:s');
                            $item->puskesmas_last_update_page = $lastPage;
                            $item->save();
                        }
                    }

                    //region Save Data Puskesmas to DB
                    foreach ($updatePuskesmas as $puskesmas) {
                        $bpjsPuskesmas = BpjsPuskesmas::findFirst([
                            'conditions' => 'kodepuskesmas = :kodepuskesmas:',
                            'bind' => [
                                'kodepuskesmas' => $puskesmas['kodepuskesmas']
                            ]
                        ]);
                        if (empty($bpjsPuskesmas)) {
                            $bpjsPuskesmas = new BpjsPuskesmas();
                        }
                        $bpjsPuskesmas->kodepuskesmas = $puskesmas['kodepuskesmas'];
                        $bpjsPuskesmas->namapuskesmas = $puskesmas['namapuskesmas'];
                        $bpjsPuskesmas->kodepropinsi = $dati2Data[0]->kodepropinsi;
                        $bpjsPuskesmas->kodepropinsikemendagri = $dati2Data[0]->kodepropinsikemendagri;
                        $bpjsPuskesmas->kodedati2 = $params['kodedati2'];
                        $bpjsPuskesmas->kodedati2kemendagri = $dati2Data[0]->kodedati2kemendagri;
                        $bpjsPuskesmas->namadati2 = $dati2Data[0]->namadati2;
                        $bpjsPuskesmas->namakec = $puskesmas['namakec'];
                        $bpjsPuskesmas->namadesa = $puskesmas['namadesa'];
                        $bpjsPuskesmas->alamat = $puskesmas['alamat'];
                        $bpjsPuskesmas->namakepala = $puskesmas['namakepala'];
                        $bpjsPuskesmas->namapenanggungjawab = $puskesmas['namapenanggungjawab'];
                        $bpjsPuskesmas->jumlahdokter = $puskesmas['jumlahdokter'];
                        $bpjsPuskesmas->jumlahdoktergigi = $puskesmas['jumlahdoktergigi'];
                        $bpjsPuskesmas->jumlahperawat = $puskesmas['jumlahperawat'];
                        $bpjsPuskesmas->jumlahapoteker = $puskesmas['jumlahapoteker'];
                        $bpjsPuskesmas->jumlahasistenapoteker = $puskesmas['jumlahasistenapoteker'];
                        $bpjsPuskesmas->jumlahbidan = $puskesmas['jumlahbidan'];
                        $bpjsPuskesmas->jumlahahligizi = $puskesmas['jumlahahligizi'];
                        $bpjsPuskesmas->listdokter = json_encode($puskesmas['listdokter']);
                        $bpjsPuskesmas->listdoktergigi = json_encode($puskesmas['listdoktergigi']);
                        $bpjsPuskesmas->tglpengajuanpaktaintegritas = $puskesmas['tglpengajuanpaktaintegritas'];
                        $status = $bpjsPuskesmas->save();
                        if (!$status) {
                            $errors = $bpjsPuskesmas->getMessage();
                            $error_messages = [];

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

                            throw new ValidationException($error_messages);
                        }
                    }
                    //endregion
                }
                catch (Exception $e) {
                    //DO NOTHING
                }
            }
        }

        $conditions = [];
        $bind = [];
        $findOptons = [
            'limit' => $params['limit'],
            'offset' => $params['offset']
        ];
        $countOptions = [];

        if(!empty($params['kodedati2'])) {
            array_push($conditions, 'kodedati2 = :kodedati2:');
            $bind['kodedati2'] = $params['kodedati2'];
        }

        if(!empty($params['namapuskesmas'])) {
            array_push($conditions, 'namapuskesmas ILIKE :namapuskesmas:');
            $bind['namapuskesmas'] = ('%' . $params['namapuskesmas'] . '%');
        }

        if(count($conditions) > 0) {
            $findOptons['conditions'] = implode(' AND ', $conditions);
            $countOptions['conditions'] = implode(' AND ', $conditions);
            $findOptons['bind'] = $bind;
            $countOptions['bind'] = $bind;
        }

        $findOptons['order'] = $validatedRequest['order_by'] . " " . $validatedRequest['order_direction'];

        $dataBpjsPuskesmas = BpjsPuskesmas::find($findOptons);
        $totalRecords = BpjsPuskesmas::count($countOptions);

        return new PaginatedResponse($dataBpjsPuskesmas, $totalRecords, $params['limit'], $params['offset']);
    }

    public function getDetailPuskesmas($kodepuskesmas) {
        $this->checkIsAuthenticated();

        $dataBpjs = BpjsPuskesmas::findFirst([
            'conditions' => 'kodepuskesmas = ?0',
            'bind' => [
                $kodepuskesmas
            ]
        ]);

        if(!empty($dataBpjs)) {
            $dataKapitasi = BpjsPuskesmasKapitasi::find([
                'conditions' => 'kodepuskesmas = ?0 AND updated_at >= ?1',
                'bind' => [
                    $kodepuskesmas,
                    date('Y-m-d', strtotime('-7 day'))
                ],
                'order' => 'bulan desc'
            ]);

            try {
                if ($dataKapitasi->count() < 1) {
                    $bpjs2Client = new Bpjs2Client($this->config['bpjs2_config']);
                    $bpjs2Client->setLogger($this->logger);
                    $resKapitasi = $bpjs2Client->getKapitasi($kodepuskesmas);
                    if ($bpjs2Client->isBpjsResponseSuccess($resKapitasi)) {
                        $list = $resKapitasi['response']['list'];
                        foreach ($list as $item) {
                            $kapitasi = BpjsPuskesmasKapitasi::findFirst([
                                'conditions' => 'kodepuskesmas = ?0 AND bulan = ?1',
                                'bind' => [
                                    $kodepuskesmas,
                                    $item['bulan']
                                ]
                            ]);
                            if (empty($kapitasi)) {
                                $kapitasi = new BpjsPuskesmasKapitasi();
                            }
                            $kapitasi->kodepuskesmas = $kodepuskesmas;
                            $kapitasi->namapuskesmas = $item['namapuskesmas'];
                            $kapitasi->bulan = $item['bulan'];
                            $kapitasi->jumlahpeserta = $item['jumlahpeserta'];
                            $kapitasi->danakapitasi = $item['danakapitasi'];
                            $kapitasi->tanggalproses = $item['tanggalproses'];
                            $kapitasi->save();
                        }

                        $dataBpjs->last_update_kapitasi = DateHelper::getNowTimezoned();
                        $dataBpjs->save();

                        $dataKapitasi = BpjsPuskesmasKapitasi::find([
                            'conditions' => 'kodepuskesmas = ?0 AND updated_at >= ?1',
                            'bind' => [
                                $kodepuskesmas,
                                date('Y-m-d', strtotime('-7 day'))
                            ],
                            'order' => 'bulan desc'
                        ]);
                    }
                }
            }
            catch (Exception $exception) {
                //DO NOTHING
            }
            $dataKapitasi = $dataKapitasi->toArray();
        } else {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, 'Puskesmas tidak ditemukan');
        }
        $dataBpjs = $dataBpjs->toArray();
        $dataBpjs['listdokter']  = json_decode($dataBpjs['listdokter']);
        $dataBpjs['listdoktergigi']  = json_decode($dataBpjs['listdoktergigi']);
        $dataBpjs['kapitasi'] = $dataKapitasi;

        return new SimpleResponse($dataBpjs);
    }

    public function getDataKapitasi($kodepuskesmas) {
        $this->checkIsAuthenticated();

        $params = $this->request->get();
        $validatedParams = $this->validate(
            $params,
            [
                "year" => ['validators' => ['digit']],
                "month" => ['validators' => ['digit']],
            ]
        );

        if(array_key_exists('month', $params)) $validatedParams['month'] = $params['month'];

        $conditions = [
            'kodepuskesmas = ?0'
        ];
        $bind = [
            $kodepuskesmas
        ];

        if(array_key_exists('month', $params) && array_key_exists('year', $params)) {
            array_push($conditions, 'TO_DATE(bulan, \'YYYY-MM\') = TO_DATE(?1, \'YYYY-MM\')');
            array_push($bind, $validatedParams['year'] . '-' . $validatedParams['month']);
        }
        else if (array_key_exists('year', $params)){
            array_push($conditions, 'bulan LIKE ?1');
            array_push($bind, $validatedParams['year'] . '%');
        }

        $kapitasi = BpjsPuskesmasKapitasi::find([
            'conditions' => implode(' AND ', $conditions),
            'bind' => $bind,
            'order' => 'bulan desc',
            'limit' => '12',
            'offset' => '0'
        ]);

        if(!$kapitasi) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "Data Kapitasi tidak ditemukan!");
        }

        return new SimpleResponse($kapitasi);
    }

    public function summaryPuskesmas($kodepuskesmas) {
        $this->checkIsAuthenticated();

        $dataBpjs = BpjsPuskesmas::findFirst([
            'conditions' => 'kodepuskesmas = ?0',
            'bind' => [
                $kodepuskesmas
            ]
        ]);

        if(empty($dataBpjs)) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, 'Puskesmas tidak ditemukan');

        }
        $conditions = [
            'kodepuskesmas = ?0'
        ];
        $bind = [
            $kodepuskesmas
        ];
        $kapitasi = BpjsPuskesmasKapitasi::find([
            'conditions' => implode(' AND ', $conditions),
            'bind' => $bind,
            'order' => 'bulan desc',
            'limit' => '12',
            'offset' => '0'
        ]);
        $dataBpjs = $dataBpjs->toArray();
        $dataBpjs['listdokter']  = json_decode($dataBpjs['listdokter']);
        $dataBpjs['listdoktergigi']  = json_decode($dataBpjs['listdoktergigi']);
        $dataBpjs['kapitasi'] = $kapitasi;

        return new SimpleResponse($dataBpjs);
    }

    public function searchNama() {
        $this->checkIsAuthenticated();

        $params = $this->request->get();

        $params['limit'] = $this->getDefaultLimit($params);
        $params['offset'] = array_key_exists('offset', $params) ? $params['offset'] : 0;
        $params['namapuskesmas'] = array_key_exists('namapuskesmas', $params) ? $params['namapuskesmas'] : "";
        $params['kodedati2'] = array_key_exists('kodedati2', $params) ? $params['kodedati2'] : "";
        $params['order_by'] = array_key_exists('order_by', $params) ? $params['order_by'] : "namapuskesmas";
        $params['order_direction'] = array_key_exists('order_direction', $params) ? $params['order_direction'] : "asc";

        $allowedOrder = ['namapuskesmas'];
        $allowedDirection = ['asc', 'desc'];

        $validatedRequest = $this->validate(
            $params,
            [
                'limit' => ['validators' => ['digit']],
                'offset' => ['validators' => ['digit']],
                'order_by' => ['validators' => [
                    [
                        'name' => 'inclusion_in',
                        'params' => $allowedOrder
                    ]
                ]],
                'order_direction' => ['validators' => [
                    [
                        'name' => 'inclusion_in',
                        'params' => $allowedDirection
                    ]
                ]],
            ]
        );

        $conditions = [];
        $bind = [];
        $findOptions = [
            'columns' => 'kodepuskesmas, namapuskesmas',
            'limit' => $params['limit'],
            'offset' => $params['offset']
        ];

        if(!empty($params['kodedati2'])) {
            $conditions[] = 'kodedati2 = :kodedati2:';
            $bind['kodedati2'] = $params['kodedati2'];
        }

        if(!empty($params['namapuskesmas'])) {
            $conditions[] = 'namapuskesmas ILIKE :namapuskesmas:';
            $bind['namapuskesmas'] = ('%' . $params['namapuskesmas'] . '%');
        }

        if(count($conditions) > 0) {
            $findOptions['conditions'] = implode(' AND ', $conditions);
            $findOptions['bind'] = $bind;
        }

        $findOptions['order'] = $validatedRequest['order_by'] . " " . $validatedRequest['order_direction'];

        $dataBpjsPuskesmas = BpjsPuskesmas::find($findOptions);

        return new CollectionPaginatedResponse($dataBpjsPuskesmas);
    }
}
