<?php

use PayPalCheckoutSdk\Core\AccessToken;

require_once('restapi.php');

class Cep extends RestApi
{
    const CEP_DB_NAME = 'cep';
    const CEP_DB_USERNAME = 'cep';
    const CEP_DB_PASSWORD = 'Fut!13@CeP@13Orc';

    public function getCep($cep)
    {
        try {
            $query = "SELECT /*+ MAX_EXECUTION_TIME(3000) */ * FROM ceps WHERE cep = " . intval($cep);
            $address = $this->query($query);

            return $address ? current($address) : $this->getCorreiosAccessToken($cep);

        } catch (Exception $e) {
            if ($e->getCode() == 70100) {
                return $this->getCorreiosAccessToken($cep);
            }

            throw $e;
        }
    }

    public function getCorreiosAccessToken($cep)
    {
        try {
            $correiosKeys = $this->getCorreiosParams();
            $accessTokenKeyDb = Crypto::descriptografarAES256($correiosKeys['correios_key'], Crypto::CAES256);
            $data = json_decode($accessTokenKeyDb, true);

            $token = $data['token'];
            $contract = $data['correioscontract'];

            // Documentação referente a API dos Correios: https://www.correios.com.br/atendimento/developers/arquivos/manual-para-integracao-correios-api e https://cws.correios.com.br/
            $url = 'https://api.correios.com.br/token/v1/autentica/contrato';
            $header = [
                'Accept: application/json',
                'Authorization: Basic ' . $token,
                'Content-Type: application/json'
            ];
            $params = [
                'numero' => $contract
            ];

            $requestApi = parent::callAPI($url, 'POST', $params, $header, false, $response, Type_DadosSend::TpDados_Json);

            $accessToken = $requestApi->token;

            return $this->searchAddressFromCorreios($cep, $accessToken);

        } catch (Exception $error) {
            throw new Exception('Erro ao gerar token dos Correios: ' . $error->getMessage());
        }
    }

    public function searchAddressFromCorreios($cep, $accessToken)
    {
        try {
            $url = 'https://api.correios.com.br/cep/v2/enderecos/' . $cep;
            $header = [
                'Accept: application/json',
                'Authorization: Bearer ' . $accessToken,
            ];

            $requestApi = parent::callAPI($url, 'GET', false, $header, false, $response, Type_DadosSend::TpDados_Json);

            return $this->getTownCode($requestApi);

        } catch (Exception $error) {
            throw new Exception('Erro ao buscar endereço via API Correios: ' . $error->getMessage());
        }
    }

    public function getTownCode($addressObject)
    {
        $address = (array) $addressObject;

        $uf = $address['uf'];
        $city = $address['localidade'];
        $url = 'https://servicodados.ibge.gov.br/api/v1/localidades/estados/' . $uf . '/municipios';

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode == 200) {
            $data = json_decode($response, true);
            $cityCode = array_filter($data, function ($town) use ($city) {
                return $town['nome'] === $city;
            });

            $cityCode = reset($cityCode);
            $address['codigo_municipio'] = $cityCode['id'];
        } else {
            $address['codigo_municipio'] = false;
        }

        return $address;
    }

    private function getCorreiosParams()
    {
        $query = $this->query('select * from parametros');

        $response = $query[0];

        return $response;
    }

    public function getCepEndereco($chave)
    {
        $chaves = explode(",", $chave);
        $inc = 0;
        $sql = ' ';
        $filtro = ' Where ';
        foreach ($chaves as $value) {
            $value = '"' . trim($value) . '"';
            if ($inc == 0)
                $sql .= "( (position(concat('|',{$value},'|')  in a.CHAVE_CONSULTA)) +
                      (position(concat({$value},'|')  in a.CHAVE_CONSULTA)) +
                      (position({$value}  in a.CHAVE_CONSULTA))";
            else
                $sql .= "+ (position(concat('|',{$value},'|')  in a.CHAVE_CONSULTA)) +
                      (position(concat({$value},'|')   in a.CHAVE_CONSULTA)) +
                      (position({$value} in a.CHAVE_CONSULTA))";

            if ($inc == 0)
                $filtro .= "( a.CHAVE_CONSULTA  like concat('%', " . $value . ", '%'))";
            else
                $filtro .= "and ( a.CHAVE_CONSULTA  like concat('%'," . $value . ", '%'))";

            $inc++;
        }

        if ($inc > 0)
            $sql .= ") ordenacao,";

        $ceps = $this->query("
            select " . $sql . "
                a.uf, a.cidade, a.bairro, a.tipo_logradouro, a.logradouro, a.logradouro_completo, a.cep, a.complemento,
                a.nome, a.chave_consulta, a.codigo_municipio
            from ceps a " . $filtro . "
            order by 1, a.logradouro, a.cidade
            limit 100");

        return $ceps ? $ceps : false;
    }

    public function query($sql)
    {
        $result = false;

        $link = mysqli_connect(DB_HOSTNAME, self::CEP_DB_USERNAME, self::CEP_DB_PASSWORD);
        $db_selected = mysqli_select_db($link, self::CEP_DB_NAME);
        if ($db_selected) {
            $query = $link->query($sql);
            if ($query) {
                $result = $query->fetch_all(MYSQLI_ASSOC);
            }
        }
        $link->close();
        return $result;
    }

}
