<?php

class Jamef extends RestApi {

  private $header;
  private $environment;
  private $branchEnvironment;
  private $accessToken;
  private $login;
  private $password;
  private $tokenExpires;
  private $retry = 0;
  private $data; 
  private $registry;
  private $load;
  private $config;
  private $log;

  public function __construct($registry) {
    $this->registry = $registry;
    $this->load     = $registry->get('load');
    $this->config   = $registry->get('config');
    $this->log      = $registry->get('log');

    $this->setEnvironment(true);
    $this->setCredentials();
    $this->setHeader();
    $this->checkAccessToken();
  }

  public function __get($name)
  {
      return $this->registry->get($name);
  }

  private function checkAccessToken(): void 
  {
    if ($this->tokenExpires < time()) {
      $this->refreshAccessToken();
    }
  }

  private function setCredentials(): void 
  {
    $this->login = $this->config->get('jamef_login');
    $this->password = $this->config->get('jamef_password');
    $this->accessToken = $this->config->get('jamef_access_token') ?? $this->accessToken;
    $this->tokenExpires = $this->config->get('jamef_token_expires') ?? time();
  }

   public function setLoginAndPassword($login, $password): void 
  {
    $this->login = $login;
    $this->password = $password;
  }

  private function setHeader($auth = true): void 
  {
    $this->header =[
      "Content-Type: application/json"
    ];

    if ($auth && $this->accessToken) {
        $this->header[] = "Authorization: Bearer " . $this->accessToken;
    }
  }

  private function getLoginUrl(): string 
  {
    if(defined('AMBIENTE_TESTE') && AMBIENTE_TESTE) {
        return "https://api-qa.jamef.com.br/auth/v1/login";
    }
    return 'https://api.jamef.com.br/auth/v1/login';
  }

  public function refreshAccessToken(): void 
  {
    try{
      $url = $this->getLoginUrl();
      $dataSend = json_encode([
          "username" => $this->login,
          "password" => $this->password
      ]);
      
      $data = parent::callAPI($url, 'POST', $dataSend, $this->getHeader(), false, $retorno);
      $this->handleErrors($data);

      $this->load->type('tipocomum');
      $this->load->model('setting/setting');

      $dataToSave = array(
          'jamef_access_token' => $data->dado[0]->accessToken,
          'jamef_token_expires' => time() + $data->dado[0]->expiresIn,
      );
      $this->accessToken = $data->dado[0]->accessToken;
      $this->tokenExpires = time() + $data->dado[0]->expiresIn;
      $this->model_setting_setting->editSettingForKey('jamef', $dataToSave);
      $this->setCredentials();
    }
    catch (Exception $ex) {
        $error = 'Erro ao carregar módulo Jamef:';
        $error.= 'Mensagem: ' . $ex->getMessage();
        $this->log->write(json_encode($error, JSON_UNESCAPED_UNICODE));
        return;
    }

    if ($this->retry == 1) {
      $this->getQuoteVolume($this->data);
    }
  }

  private function getHeader():array 
  {
    return $this->header;
  }

  private function setEnvironment(): void 
  {
    $this->environment = 'https://api.jamef.com.br/calculo-frete/v1/';
    
    if(defined('AMBIENTE_TESTE') && AMBIENTE_TESTE) {
        $this->environment = "https://api-qa.jamef.com.br/calculo-frete/v1/";
    }
  }

  private function setBranchEnvironment(): void 
  {
    $this->branchEnvironment = 'https://api.jamef.com.br/infraestrutura/v1/';
    
    if(defined('AMBIENTE_TESTE') && AMBIENTE_TESTE) {
        $this->branchEnvironment = "https://api-qa.jamef.com.br/infraestrutura/v1/";
    }
  }

  private function getEnvironment(): string 
  {
    return $this->environment;
  }

  private function getBranchEnvironment(): string 
  {
    return $this->branchEnvironment;
  }

  private function handleErrors($data): void 
  {
    if (!is_object($data)) {
        $error = 'Erro ao carregar módulo Jamef:';
        $error.= 'Mensagem: Erro na conexão com o Jamef';
        $this->log->write(json_encode($error, JSON_UNESCAPED_UNICODE));
        throw new Exception($error);
    }
    else if(property_exists($data, 'situacao') && property_exists($data, 'erros') && ($data->situacao != 401 || ( $data->situacao == 401 && $this->retry > 0))) {
        $error = 'WARNING ao carregar módulo Jamef:';
        $error.= 'Código: '.$data->situacao;
        $error.= ' Mensagem: ';
        foreach ($data->erros as $key => $erro) {
            $error.= " - " . $key . " - " . $erro->detalhes;
        }
        $this->log->write(json_encode($error, JSON_UNESCAPED_UNICODE));
        throw new Exception($error);
    }
    else if (property_exists($data, 'error')) {
        if (($this->retry > 0 && $data->error == 'Invalid token.') || $data->error != 'Invalid token.') {
          $this->header = [];
          $error = 'Erro ao carregar módulo Jamef:';
          $error.= 'Mensagem: ' . (is_string($data->error) ? $data->error: json_encode($data->error));
          $this->log->write(json_encode($error, JSON_UNESCAPED_UNICODE));
          throw new Exception($error);
        }
    }
    else if (property_exists($data, 'erros') || (!property_exists($data, 'situacao'))) {
        $error = 'Erro ao carregar módulo Jamef:';
        $error.= 'Mensagem: Erro no retorno com o Jamef';
        $this->log->write(json_encode($error, JSON_UNESCAPED_UNICODE));
        throw new Exception($error);
    }
  }

  public function getQuoteVolume($dataSend): mixed
  {
    $url = $this->getEnvironment() . 'cotacao';
    $data = parent::callAPI($url, 'POST', $dataSend, $this->getHeader(), false, $retorno);

    $this->handleErrors($data);

    switch($retorno) {
        case 200: 
            $this->retry = 0;
            return $data->dado[0];
            break;
        case 401: 
            $this->retry++;
            $this->data = $dataSend;
            $this->refreshAccessToken();
            break;
        default: $this->handleErrors($data);
            break;
    }
    return $data;
  }

  public function getBranches($postCode = null)
  {
    $this->setBranchEnvironment();
    $this->setHeader();
    $complement = $postCode ? '?cep='. $postCode : '';
    $url = $this->getBranchEnvironment() . 'lista-filiais' . $complement;
    $data = parent::callAPI($url, 'GET', null, $this->getHeader(), false, $retorno);

    $this->handleErrors($data);

    switch($retorno) {
        case 200: 
            $this->saveBranches($data->dado);
            break;
        case 401: 
            $this->retry++;
            $this->refreshAccessToken();
            break;
        default: $this->handleErrors($data);
            break;
    }
  }

  public function saveBranches($branchData) {
    $branchData = $this->translateBranches($branchData);
    $this->load->type('tipocomum');
    $this->load->model('setting/setting');

    $dataToSave = array(
        'jamef_lista_filiais' => json_encode($branchData),
        'jamef_lista_filiais_save' => time()
    );

    $this->model_setting_setting->editSettingForKey('jamef', $dataToSave);
  }  

  public function translateBranches($branches): array {
      $branches = is_array($branches) ? $branches : json_decode($branches);
      $branchData = [];
      foreach ($branches as $branch) {
        $branchData[$branch->codigoFilial] = $branch->codigoFilial . ' - (' . $branch->siglaFilial . ') ' . ucwords($branch->nomeFilial) . '/' . $branch->uf;
      }
      return $branchData;
  }
}
