<?php
declare(strict_types=1);

/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link      https://cakephp.org CakePHP(tm) Project
 * @since     0.2.9
 * @license   https://opensource.org/licenses/mit-license.php MIT License
 */
namespace App\Controller;

/**
 * Application Controller
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @link https://book.cakephp.org/4/en/controllers.html#the-app-controller
 */
class ApiController extends AppController
{
    /**
     * Initialization hook method.
     *
     * Use this method to add common initialization code like loading components.
     *
     * e.g. `$this->loadComponent('FormProtection');`
     *
     * @return void
     */

    private $ip;

    private $data = [];
    private $count = -1;
    private $handle = null;
    private $query = '';

    public function initialize(): void {        
        parent::initialize();
        $this->Authentication->allowUnauthenticated(['notification', 'processFileSlowQueries']);
        $this->autoRender = false;
        $this->checkIpAuth();
    }

    private function checkIpAuth(){
        $resp = ['error' => 'Acceso denegado'];
        $denied = false;

        $this->ip = $this->request->clientIp();
        $this->loadModel('IpAuths');
        $access = $this->IpAuths->find()->where(['ip' => $this->ip])->first();
        
        if(!$access){
            $ipAuth = $this->IpAuths->newEmptyEntity();
            $token = $this->generateToken();

            $data = [
                'ip' => $this->ip,
                'token' => $token
            ];

            $ipAuth = $this->IpAuths->patchEntity($ipAuth, $data);
            $this->IpAuths->save($ipAuth);
            $denied = true;
        }else{
            $token = $this->request->getQuery('t') ?? null;

            if($token){
                $access = $this->IpAuths->find()->where(['token' => $token])->first();

                if($access){
                    if($this->ip != $access['ip']){
                        $denied = true;
                    }elseif(!$access->auth){
                        $denied = true;
                    }
                }else{
                    $denied = true;
                }
            }else{
                $denied = true;
            }
        }

        if($denied){
            $this->notification('alerts', 'Acceso denegado para ip '.$this->ip, false);
            $this->response($resp);
            exit;
        }
    }

    public function notification($chatName = 'alerts', $mssg = '', $return = true){

        $this->loadModel('Chatbots');
        $chat = $this->Chatbots->find()->where(['name' => $chatName])->first();

        if($chat){
            $this->loadModel('Notifications');
            $notif = $this->Notifications->newEmptyEntity();

            $data = [
                'ip' => $this->ip,
                'chatbot_id' => $chat->id,
                'message' => $mssg
            ];

            $notif = $this->Notifications->patchEntity($notif, $data);
            $this->Notifications->save($notif);

            $send = $this->sendMessage($chat->token, $chat->chatid, $mssg);

            if($send['ok']){
                $this->Notifications->updateAll(['send' => 1], ['id' => $notif->id]);
                $resp = ['result' => true, 'msg' => 'Mensaje enviado'];
            }else{
                $resp = ['result' => false, 'msg' => 'Mensaje no enviado'];
            }
        }else{
            $resp = ['result' => false, 'mssg' => 'Chat no valido'];
        }

        if($return)
            return $this->response($resp);
    }

    public function processFileSlowQueries(){

        $path = dirname(__FILE__).'\..\..';
        $file = $path.'\mysql-slow.log';
        $date = date('YmdHis');
        $save = true;

        if(!file_exists($file)){
            $response = ['result' => false, 'mssg' => 'El archivo no existe o no está en la ruta especificada'];
        }else{
            if(true/*rename($path.'\mysql-slow.log', $path.'\mysql-slow-'.$date.'.log')*/){
                $this->handle = @fopen($path.'\mysql-slow.log', 'r');

                if ($this->handle) {
                    while (($line = fgets($this->handle)) !== false) {
                        $this->processLine(trim($line));
                    }

                    #pr($this->data);
                    fclose($this->handle);

                    $this->loadModel('SlowQueries');

                    foreach ($this->data as $k => $slow) {
                        $slowQuery = $this->SlowQueries->newEmptyEntity();
                        $slowQuery = $this->SlowQueries->patchEntity($slowQuery, $slow);

                        if(!$this->SlowQueries->save($slowQuery)){
                            $save = false;
                        }

                    }

                    if($save){
                        $response = ['result' => true, 'mssg' => 'Archivo procesado'];
                    }else{
                        $response = ['result' => false, 'mssg' => 'Algunas de las consultas no pudieron ser registradas'];
                    }

                }else{
                    $response = ['result' => false, 'mssg' => 'El archivo de slow queries no se pudo leer'];
                }
            }
        }

        return $this->response($response ?? []);

    }

    private function processLine($line = null, $continue = false){

        if($line){

            if(preg_match('/# User@Host:/', $line)){
                $line = explode(' ', $line);
                $this->count++;

                $this->data[$this->count]['user'] = $line[2];
            }else{
                if(preg_match('/^# Thread_id:/', $line)){

                    $line = explode('  ', $line);
                    $this->data[$this->count]['schema'] = explode(': ', $line[1])[1] ?? '';

                }elseif(preg_match('/^# Query_time/', $line)){

                    $line = preg_replace('/# /', '', $line);
                    $line = explode('  ', $line);
                    $attr = [];

                    foreach($line as $el){
                        $val = explode(': ', trim($el));
                        $this->data[$this->count][strtolower($val[0])] = $val[1];
                    }

                }elseif(preg_match('/^SET/', $line)){

                    $time = preg_replace('/;/', '', $line);
                    $time = trim(explode('=', $time)[1] ?? '');
                    $this->data[$this->count]['date'] = $time;#date('Y-m-d H:i:s', trim($time));

                }elseif(preg_match('/^(SELECT|select|UPDATE|update|DELETE|delete|INSERT|insert|ALTER|alter|CREATE|create)/', $line) || $continue){

                    $isEnd = preg_match('/;$/', $line);

                    $this->query .= ' '.$line;

                    if(!$isEnd){
                        $line = fgets($this->handle);
                        $this->processLine(trim($line), true);
                    }else{
                        $this->data[$this->count]['query'] = $this->query;
                        $this->query = '';
                    }

                }
            }

        }else{
            return false;
        }
    }

}
