<?php

namespace Teknisa\Libs\Controller;

use Teknisa\Libs\Exception\CustomException;
use Teknisa\Libs\Util\InstanceProvider;
use Teknisa\Libs\Util\OAuthCustom;
use Teknisa\Libs\Util\Utilities;
use Zeedhi\Framework\Controller\Simple;
use Zeedhi\Framework\DTO\Request;
use Zeedhi\Framework\DTO\Response;
use Zeedhi\Framework\DataSource\DataSet;
use Zeedhi\Framework\HTTP\Kernel;
use Teknisa\Libs\Service\Api as ApiService;
use Zeedhi\Framework\HTTP\Response\JSON;

Class Api extends Simple {
    /** @var OAuthImpl $oauth */
    private $oauth;
    /** @var Kernel $kernel */
    private $kernel;
    /** @var ApiService $apiService */
    private $apiService;

    public function __construct(OAuthCustom $oauth, Kernel $kernel, ApiService $apiService) {
        $this->oauth = $oauth;
        $this->kernel = $kernel;
        $this->apiService = $apiService;
    }

    public function requestToken(Request $request, Response $response) {
        try {
            $httpRequest = $this->kernel->getHttpRequest();
            $clientId = $httpRequest->get('CLIENT_ID');
            $clientSecret = $httpRequest->get('CLIENT_SECRET');
            $token = $this->oauth->grantAccessToken($clientId, $clientSecret, array('sessionId' => InstanceProvider::getSession()->getId()));
            $response->addDataSet(new DataSet('token', array($token)));
        } catch (\Exception $e){
            $response->setError(new Response\Error($e->getMessage(), Response\Message::TYPE_ERROR));
        }

    }

    public function getUserData(Request\Filter $request, Response $response) {
        try {
            $conditions = $request->getFilterCriteria()->getConditions();
            $user = Utilities::getValueInFilterDataSourceByName($conditions, 'USER');
            $password = Utilities::getValueInFilterDataSourceByName($conditions, 'PASSWORD');
            $userData = $this->apiService->getUserData($user, $password);
            $response->addDataSet(new DataSet('userData', $userData));
        } catch (\Exception $e){
            $response->setError(new Response\Error($e->getMessage(), Response\Message::TYPE_ERROR));
        }
    }

    public function updatePassword(Request\Filter $request, Response $response) {
        try {
            $conditions = $request->getFilterCriteria()->getConditions();
            $email = Utilities::getValueInFilterDataSourceByName($conditions, 'EMAIL');
            $password = Utilities::getValueInFilterDataSourceByName($conditions, 'PASSWORD');
            $identification = Utilities::getValueInFilterDataSourceByName($conditions, 'IDENTIFICATION');
            $this->apiService->updatePassword($email, $password, $identification);
        } catch (\Exception $e){
            $response->setError(new Response\Error($e->getMessage(), Response\Message::TYPE_ERROR));
        }
    }

    public function validateUser(Request\Filter $request, Response $response) {
        try {
            $conditions     = $request->getFilterCriteria()->getConditions();
            $user           = Utilities::getValueInFilterDataSourceByName($conditions, 'USER');
            $password       = Utilities::getValueInFilterDataSourceByName($conditions, 'PASSWORD');
            $userValidation = $this->apiService->validateUser($user, $password);
            $response->addDataSet(new DataSet('userValidation', $userValidation));
        } catch(\Exception $e) {
            $response->setError(new Response\Error($e->getMessage(), 500));
        }
    }

    public function getModulesVersion(Request\Filter $request, Response $response) {
        try {
            $modulesVersion = $this->apiService->getModulesVersion();
            $response->addDataSet(new DataSet('modulesVersion', $modulesVersion));
        } catch(CustomException $e) {
            $response->setError(Utilities::getErrorObjectFromException($e));
        }
    }

    public function generateModulesVersionFile(Request\DataSet $request, Response $response) {
        try {
            $generatedFile = $this->apiService->generateModulesVersionFile();
            $response->addDataSet(new DataSet('generatedFile', array($generatedFile)));
        } catch(\Exception $e) {
            $response->setError(new Response\Error($e->getMessage(), 500));
        }
    }

    public function downloadModulesVersionFile(Request\DataSet $request, Response $response) {
        try {
            $row = $request->getDataSet()->getRows()[0];
            $fileName = $row['FILE_NAME'];
            $this->apiService->downloadLoginAccessFile($fileName);
        } catch(\Exception $e) {
            $response->setError(new Response\Error($e->getMessage(), 500));
        }
    }

    public function testConnection(Request $request, Response $response) {
        try {
            $response->addDataSet(new DataSet('connection', array(true)));
        } catch (\Exception $e){
            $response->setError(new Response\Error($e->getMessage(), Response\Message::TYPE_ERROR));
        }
    }

    public function updateTranslation(Request $request, Response $response) {
        try {
            ini_set("memory_limit", "8192M");
            ini_set('max_execution_time', '300');
            set_time_limit(300);
            $this->apiService->updateTranslation();
            $response->addDataSet(new DataSet('updateTranslation', array(true)));
        } catch (\Exception $e){
            $response->setError(new Response\Error($e->getMessage(), Response\Message::TYPE_ERROR));
        }
    }

    public function openReport(Request $request, Response $response) {
        try {
            ini_set("memory_limit", "1024M");
            ini_set('max_execution_time', '1800');
            set_time_limit(1800);
            $row = $request->getDataSet()->getRows()[0];
            $key = $row['KEY'];
            $this->apiService->openReport($key);
        } catch (\Exception $e){
            $response->setError(new Response\Error($e->getMessage(), Response\Message::TYPE_ERROR));
        }
    }

    public function downloadPHPErrorLog(Request $request, Response $response) {
        try {
            ini_set("memory_limit", "1024M");
            ini_set('max_execution_time', '300');
            set_time_limit(300);
            $token = $request->getParameter('token');
            $filename = $request->getParameter('filename');
            $this->apiService->downloadPHPErrorLog($token, $filename);
        } catch (\Exception $e) {
            $message = $e->getMessage();
            if($message == 'INVALID_TOKEN' || $message == 'EXPIRED_TOKEN' ) {
                $message = 'Token de sessão inválido';
            }
            echo '<h3>' . $message . '<h3>';
            die;
        }
    }

    public function getPHPErrorLogFiles(Request $request, Response $response) {
        try {
            $files = $this->apiService->getPHPErrorLogFiles();
            $response->addDataSet(new DataSet('getPHPErrorLogFiles', $files));
        } catch(CustomException $e) {
            $response->setError(Utilities::getErrorObjectFromException($e));
        }
    }

    public function chatBotQuery(Request $request, Response $response) {
        try {
            $params = $request->getParameters();
            $key = "12345678901234567890123456789012"; // 32 bytes para AES-256
            $iv  = "1234567890123456";                 // 16 bytes
    
            $encryptedSQL  = $params['SQL'];
            $rawEncrypted  = base64_decode($encryptedSQL);
            $decryptedSQL  = openssl_decrypt($rawEncrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    
            $decryptedSQLParams = [];
            if (isset($params['SQL_PARAMS'])) {
                foreach ($params['SQL_PARAMS'] as $paramName => $encryptedValueBase64) {
                    $rawEncryptedParam = base64_decode($encryptedValueBase64);
                    $decryptedValue = openssl_decrypt($rawEncryptedParam, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
                    $decryptedSQLParams[$paramName] = $decryptedValue;
                }
            }

            $data = $this->apiService->chatBotQuery($decryptedSQL, $decryptedSQLParams);
            
            $this->sendResponse($data, 200);
        } catch (\Exception $e){
            $this->sendResponse(['error' => $e->getMessage(), 'code' => $e->getCode()], 500);
        }
    }

    public function sendResponse($content, $statusCode)
    {
        $kernelResponse = new JSON($content, $statusCode);
        $responseHeaders = $kernelResponse->getHeaders();
        $responseHeaders->set('Content-type', 'application/json');
        $kernelResponse->send();
        die;
    }
}