<?php

require_once(__DIR__ . '/../../sistemawin7lib/vendor/autoload.php');

use Detection\MobileDetect;
use Win7\Ads\Entity\CustomerFilter;
use Win7\Ads\Repository\AdGroupRepository;
use Win7\Ads\Repository\CampaignRepository;
use Win7\App;

/**
 * Classe responsável pelas consultas do ads.
 */
class Sistema_Adwords
{

    /**
     * @var \Banco_Dados
     */
    private $bd;

    /**
     * Construtor.
     *
     * @param \Banco_Dados $bd
     */
    public function __construct(Banco_Dados $bd)
    {
        $this->bd = $bd;
    }

    /**
     * Trata alguma exceção ocorrida.
     * Função precisa ser melhorada, após a migração a forma de tratamento de erros está muito diferente
     *
     * @param $exception
     * @return void
     */
    public function tratar_excecao($exception)
    {
        echo "-2Houve um erro com o servidor do Google Ads.";
        exit;
    }

    /**
     * Função que bloqueia um IP em todas as campanhas de um certo cliente com certa ID.
     *
     * @param $id
     * @param $ip
     * @return void
     * @throws \DI\DependencyException
     * @throws \DI\NotFoundException
     * @throws \Exception
     */
    function bloquear_ip($id, $ip)
    {
        $dados  = $this->bd->executar(
            "SELECT NU_ADWORDS FROM TBL_CLIENTE WHERE ID_CLIENTE = :id",
            [':id' => $id],
            Banco_Dados::FETCH
        );
        $filter = new CustomerFilter();
        $filter->setCustomerId($dados['NU_ADWORDS']);
        App::initialize();
        $repository  = App::getContainer()->get(CampaignRepository::class);
        $idCampanhas = array_map(function (array $dados) {
            return $dados['campaign']['id'];
        }, $repository->getList($filter));
        $repository->blockIp($filter, $idCampanhas, $ip);
    }

    /**
     * Retorna todos os grupos de anúncios.
     *
     * @param \Win7\Ads\Entity\CustomerFilter $filter
     * @return array
     * @throws \DI\DependencyException
     * @throws \DI\NotFoundException
     * @throws \Exception
     */
    public function grupos_adwords(CustomerFilter $filter): array
    {
        App::initialize();
        $rows = App::getContainer()->get(AdGroupRepository::class)->getList($filter);

        $grupos = [];

        foreach ($rows as $row) {
            $grupos[] = [
                "nome"         => $row['adGroup']['name'],
                "id"           => $row['adGroup']['id'],
                "campanhaId"   => $row['campaign']['id'],
                "campanhaNome" => $row['campaign']['name'],
            ];
        }

        return $grupos;
    }

    /**
     * Formata o número especificado utilizando padrões do adwords.
     *
     * @param $numero
     * @return string
     */
    public static function formatar_numero($numero): string
    {
        return number_format((string)$numero, 0, ',', '.');
    }

    /**
     * Formata o a quantidade monetária especificada utilizando padrões do adwords
     *
     * @param $numero
     * @param int $convencao
     * @return string
     */
    public static function formatar_valor($numero, int $convencao = 0): string
    {
        switch ($convencao) {
            case Sistema::MOEDA_REAL:
                $valor = floatval(strval($numero)) / 1000000;

                return 'R$ ' . number_format($valor, 2, ',', '.');
            case Sistema::MOEDA_DOLAR:
                $valor = floatval(intval(strval($numero))) / 1000000;

                return '$ ' . number_format($valor, 2, '.', ',');
            case Sistema::MOEDA_EURO:
                $valor = floatval(intval(strval($numero))) / 1000000;

                return '€ ' . number_format($valor, 2, '.', ',');
            default:
                return "";
        }
    }

    /**
     * Formata o a quantidade monetária especificada utilizando padrões do adwords
     *
     * @param $numero
     * @return string
     */
    public static function formatar_valor_sem_icone_moeda($numero): string
    {
        return number_format(floatval(strval($numero)) / 1000000, 2);
    }

    /**
     * Calcula o custo por lead
     *
     * @param $numero
     * @param $leads
     * @param int $convencao
     * @return array|string[]
     */
    public static function calcular_custo_lead($numero, $leads, int $convencao = 0): array
    {
        switch ($convencao) {
            case Sistema::MOEDA_REAL:
                $valor = floatval(strval($numero)) / 1000000;
                if ($leads > 0) {
                    $valor /= $leads;
                }
                $valor2 = 'R$ ' . number_format($valor, 2, ',', '.');

                return [$valor, $valor2];
            case Sistema::MOEDA_DOLAR:
                $valor = floatval(intval(strval($numero))) / 1000000;
                if ($leads > 0) {
                    $valor /= $leads;
                }
                $valor2 = '$ ' . number_format($valor, 2, '.', ',');

                return [$valor, $valor2];
            case Sistema::MOEDA_EURO:
                $valor = floatval(intval(strval($numero))) / 1000000;
                if ($leads > 0) {
                    $valor /= $leads;
                }
                $valor2 = '€ ' . number_format($valor, 2, '.', ',');

                return [$valor, $valor2];
            default:
                return ["", ""];
        }
    }

    /**
     * Calcula o custo por lead
     *
     * @param $numero
     * @param $leads
     * @return array
     */
    public static function calcular_custo_lead_sem_icone_moeda($numero, $leads): array
    {
        $valor = floatval(strval($numero)) / 1000000;
        if ($leads > 0) {
            $valor /= $leads;
        }
        $valor2 = number_format($valor, 2);

        return [$valor, $valor2];
    }

    /**
     * Verifica se o usuário está acessando a página e bloqueia o IP dele no adwords no primeiro acesso
     *
     * @param $id_cliente
     * @return void
     */
    public function verificar_bloqueio_ip_e_bloquear_instantaneo($id_cliente)
    {
        error_reporting(0);
        ignore_user_abort(true);
        session_name("adwordsbloqueionahora" . $id_cliente);
        session_start();

        try {
            $dados         = $this->bd->executar(
                "SELECT NU_ADWORDS FROM TBL_CLIENTE WHERE ID_CLIENTE = :id",
                [':id' => $id_cliente],
                Banco_Dados::FETCH
            );
            $id_do_adwords = $dados['NU_ADWORDS'];
            if (empty($id_do_adwords)) {
                return;
            }

            $detect = new MobileDetect();

            /* Pega o IP do Usuário */
            $ip = empty($_SERVER['HTTP_CLIENT_IP']) ?
                (empty($_SERVER['HTTP_X_FORWARDED_FOR']) ?
                    $_SERVER['REMOTE_ADDR']
                    : $_SERVER['HTTP_X_FORWARDED_FOR'])
                : $_SERVER['HTTP_CLIENT_IP'];

            /* Pega os horarios e verifica se esta acessando muito rapido */
            if (empty($_SESSION['hora'])) {
                $_SESSION['hora'] = date('H:i:s');
            }
            $horaAtual        = date('H:i:s');
            $data1            = new DateTime($horaAtual);
            $horaUltimoAcesso = $_SESSION['hora'];
            $data2            = new DateTime($horaUltimoAcesso);
            $intervalo        = $data1->diff($data2);

            /* Conta os acesso a pagina */
            if (empty($_SESSION['contador'])) {
                $_SESSION['contador'] = 0;
            }
            $_SESSION['contador'] += 1;

            /* Calcula os segundos do ultimo acesso e a quantidade de acessos */
            // if (($intervalo->s < $segundos_bloqueio && $intervalo->i < 1 && $_SESSION['contador'] > 1) || $_SESSION['contador'] > $qtd_cliques_max) { /* 10 segundos ou mais que 4 acessos */

            $IPBloqueado = $this->buscar_ip_banco($id_cliente, $ip);
            if ($ip != $IPBloqueado) {
                /* Executa funcao para salvar IP no banco */
                $this->salvar_ip_banco(
                    $ip,
                    $id_cliente,
                    $horaAtual,
                    $interv = $intervalo->i . " min e " . $intervalo->s,
                    $_SESSION['contador']
                );

                try {
                    /* Chama a funcao para adiciona o IP na lista da IP Bloqueados do AdWords */
                    $this->bloquear_ip($id_cliente, $ip);
                } catch (Exception $e) {
                    $this->salvar_erro_ip_banco('Erro #1: ' . $e->getMessage(), $id_cliente);
                }
            }
            // }

            /* Se existir o IP no Banco, ele altera a quantidade de acessos */
            $IPBloqueado = $this->buscar_ip_banco($id_cliente, $ip);
            if ($ip == $IPBloqueado) {
                /* Salva a quantidade de acessos */
                $this->salvar_qtd_tentativas_ip($_SESSION['contador'], $ip);
            }

            /* Salva se for MOBILE */
            if ($detect->isMobile()) {
                $dispositivo = "Smartphone";
            }

            /* Salva se for TABLET */
            if ($detect->isTablet()) {
                $dispositivo = "Tablet";
            }

            /* Salva se não for MOBILE nem TABLET */
            if (!$detect->isMobile() && !$detect->isTablet()) {
                $dispositivo = "Computador";
            }

            /* Chama a funcao para salvar o dispositivo */
            $this->salvar_dispositivo_ip($dispositivo, $ip);

            /* Pega o IP Acessado */
            $_SESSION['ultimoIPAcessado'] = $ip;

            /* Pega a hora atual acessada */
            $_SESSION['hora'] = date('H:i:s');
        } catch (Exception $e) {
        }
    }

    /**
     * Verifica se o usuário está acessando a página com muita frequência, e bloqueia o IP dele no adwords caso esteja
     *
     * @param $id_cliente
     * @param $qtd_cliques_max
     * @param $segundos_bloqueio
     * @return void
     */
    public function verificar_bloqueio_ip($id_cliente, $qtd_cliques_max = 2, $segundos_bloqueio = 600)
    { /* 600 = 10 min */
        error_reporting(0);
        ignore_user_abort(true);
        session_name("adwords" . $id_cliente);
        session_start();

        try {
            $dados         = $this->bd->executar(
                "SELECT NU_ADWORDS FROM TBL_CLIENTE WHERE ID_CLIENTE = :id",
                [':id' => $id_cliente],
                Banco_Dados::FETCH
            );
            $id_do_adwords = $dados['NU_ADWORDS'];
            if (empty($id_do_adwords)) {
                return;
            }

            $detect = new MobileDetect();

            /* Pega o IP do Usuário */
            $ip = empty($_SERVER['HTTP_CLIENT_IP']) ?
                (empty($_SERVER['HTTP_X_FORWARDED_FOR']) ?
                    $_SERVER['REMOTE_ADDR']
                    : $_SERVER['HTTP_X_FORWARDED_FOR'])
                : $_SERVER['HTTP_CLIENT_IP'];

            /* Pega os horarios e verifica se esta acessando muito rapido */
            if (empty($_SESSION['hora'])) {
                $_SESSION['hora'] = date('H:i:s');
            }
            $horaAtual        = date('H:i:s');
            $data1            = new DateTime($horaAtual);
            $horaUltimoAcesso = $_SESSION['hora'];
            $data2            = new DateTime($horaUltimoAcesso);
            $intervalo        = $data1->diff($data2);

            /* Conta os acesso a pagina */
            if (empty($_SESSION['contador'])) {
                $_SESSION['contador'] = 0;
            }
            $_SESSION['contador'] += 1;

            /* Calcula os segundos do ultimo acesso e a quantidade de acessos */
            if (($intervalo->s < $segundos_bloqueio && $intervalo->i < 1 && $_SESSION['contador'] > 1) || $_SESSION['contador'] > $qtd_cliques_max) { /* 10 segundos ou mais que 4 acessos */

                $IPBloqueado = $this->buscar_ip_banco($id_cliente, $ip);
                if ($ip != $IPBloqueado) {
                    /* Executa funcao para salvar IP no banco */
                    $this->salvar_ip_banco(
                        $ip,
                        $id_cliente,
                        $horaAtual,
                        $interv = $intervalo->i . " min e " . $intervalo->s,
                        $_SESSION['contador']
                    );

                    try {
                        /* Chama a funcao para adiciona o IP na lista da IP Bloqueados do AdWords */
                        $this->bloquear_ip($id_cliente, $ip);
                    } catch (Exception $e) {
                        $this->salvar_erro_ip_banco('Erro #1: ' . $e->getMessage(), $id_cliente);
                    }
                }
            }

            /* Se existir o IP no Banco, ele altera a quantidade de acessos */
            $IPBloqueado = $this->buscar_ip_banco($id_cliente, $ip);
            if ($ip == $IPBloqueado) {
                /* Salva a quantidade de acessos */
                $this->salvar_qtd_tentativas_ip($_SESSION['contador'], $ip);
            }

            /* Salva se for MOBILE */
            if ($detect->isMobile()) {
                $dispositivo = "Smartphone";
            }

            /* Salva se for TABLET */
            if ($detect->isTablet()) {
                $dispositivo = "Tablet";
            }

            /* Salva se não for MOBILE nem TABLET */
            if (!$detect->isMobile() && !$detect->isTablet()) {
                $dispositivo = "Computador";
            }

            /* Chama a funcao para salvar o dispositivo */
            $this->salvar_dispositivo_ip($dispositivo, $ip);

            /* Pega o IP Acessado */
            $_SESSION['ultimoIPAcessado'] = $ip;

            /* Pega a hora atual acessada */
            $_SESSION['hora'] = date('H:i:s');
        } catch (Exception $e) {
        }
    }

    /**
     * Verifica se o usuário está acessando a página com muita frequência, e bloqueia o IP dele no adwords caso esteja
     *
     * @param $id_cliente
     * @param $qtd_cliques_max
     * @param $segundos_bloqueio
     * @return void
     */
    public function verificar_bloqueio_ip_umacesso($id_cliente, $qtd_cliques_max = 0, $segundos_bloqueio = 0)
    {
        error_reporting(0);
        ignore_user_abort(true);
        session_name("adwords" . $id_cliente);
        session_start();

        try {
            $dados         = $this->bd->executar(
                "SELECT NU_ADWORDS FROM TBL_CLIENTE WHERE ID_CLIENTE = :id",
                [':id' => $id_cliente],
                Banco_Dados::FETCH
            );
            $id_do_adwords = $dados['NU_ADWORDS'];
            if (empty($id_do_adwords)) {
                return;
            }

            $detect = new MobileDetect();

            /* Pega o IP do Usuário */
            $ip = empty($_SERVER['HTTP_CLIENT_IP']) ?
                (empty($_SERVER['HTTP_X_FORWARDED_FOR']) ?
                    $_SERVER['REMOTE_ADDR']
                    : $_SERVER['HTTP_X_FORWARDED_FOR'])
                : $_SERVER['HTTP_CLIENT_IP'];

            /* Pega os horarios e verifica se esta acessando muito rapido */
            if (empty($_SESSION['hora'])) {
                $_SESSION['hora'] = date('H:i:s');
            }
            $horaAtual        = date('H:i:s');
            $data1            = new DateTime($horaAtual);
            $horaUltimoAcesso = $_SESSION['hora'];
            $data2            = new DateTime($horaUltimoAcesso);
            $intervalo        = $data1->diff($data2);

            /* Conta os acesso a pagina */
            if (empty($_SESSION['contador'])) {
                $_SESSION['contador'] = 0;
            }
            $_SESSION['contador'] += 1;

            /* Calcula os segundos do ultimo acesso e a quantidade de acessos */
            if (($intervalo->s < $segundos_bloqueio && $intervalo->i < 1 && $_SESSION['contador'] > 0) || $_SESSION['contador'] > $qtd_cliques_max) { /* 10 segundos ou mais que 4 acessos */

                $IPBloqueado = $this->buscar_ip_banco($id_cliente, $ip);
                if ($ip != $IPBloqueado) {
                    /* Executa funcao para salvar IP no banco */
                    $this->salvar_ip_banco(
                        $ip,
                        $id_cliente,
                        $horaAtual,
                        $interv = $intervalo->i . " min e " . $intervalo->s,
                        $_SESSION['contador']
                    );

                    try {
                        /* Chama a funcao para adiciona o IP na lista da IP Bloqueados do AdWords */
                        $this->bloquear_ip($id_cliente, $ip);
                    } catch (Exception $e) {
                        $this->salvar_erro_ip_banco('Erro #1: ' . $e->getMessage(), $id_cliente);
                    }
                }
            }

            /* Se existir o IP no Banco, ele altera a quantidade de acessos */
            $IPBloqueado = $this->buscar_ip_banco($id_cliente, $ip);
            if ($ip == $IPBloqueado) {
                /* Salva a quantidade de acessos */
                $this->salvar_qtd_tentativas_ip($_SESSION['contador'], $ip);
            }

            /* Salva se for MOBILE */
            if ($detect->isMobile()) {
                $dispositivo = "Smartphone";
            }

            /* Salva se for TABLET */
            if ($detect->isTablet()) {
                $dispositivo = "Tablet";
            }

            /* Salva se não for MOBILE nem TABLET */
            if (!$detect->isMobile() && !$detect->isTablet()) {
                $dispositivo = "Computador";
            }

            /* Chama a funcao para salvar o dispositivo */
            $this->salvar_dispositivo_ip($dispositivo, $ip);

            /* Pega o IP Acessado */
            $_SESSION['ultimoIPAcessado'] = $ip;

            /* Pega a hora atual acessada */
            $_SESSION['hora'] = date('H:i:s');
        } catch (Exception $e) {
        }
    }

    /**
     * Salva os possíveis erros no banco
     *
     * @param $erro
     * @param $id
     * @return bool
     */
    public function salvar_erro_ip_banco($erro, $id)
    {
        try {
            /* Conecta com o banco para inserir os dados */
            $this->bd->executar(
                'UPDATE TBL_IP_ADWORDS SET ERRO = :ERRO WHERE ID_CLIENTE = :ID_CLIENTE',
                [
                    ':ERRO'       => $erro,
                    ':ID_CLIENTE' => $id,
                ]
            );

            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Funcao para buscar o IP no banco, para ver se ele existe
     *
     * @param $id
     * @param $ip
     * @return false|mixed|string
     */
    public function buscar_ip_banco($id, $ip)
    {
        try {
            $IPBanco = "";

            /* Conecta com o banco para inserir os dados */
            $dados = $this->bd->executar(
                "SELECT IP FROM TBL_IP_ADWORDS WHERE ID_CLIENTE = '$id' AND IP = '$ip' ",
                [],
                Banco_Dados::FETCH_ALL
            );
            $qtde  = count($dados);
            if ($qtde > 0) {
                foreach ($dados as $row) {
                    $IPBanco = $row['IP'];
                }
            }

            return $IPBanco;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Funcao para salvar IP no Banco
     *
     * @param $ip
     * @param $id
     * @param $horaAtual
     * @param $interv
     * @param $tentativaAtual
     * @return bool
     */
    public function salvar_ip_banco($ip, $id, $horaAtual, $interv, $tentativaAtual)
    {
        try {
            /* Conecta com o banco para inserir os dados */
            $this->bd->executar(
                'INSERT INTO TBL_IP_ADWORDS (IP,ID_CLIENTE,HORA_ACESSO,INTERVALO,TENTATIVA) VALUES (:IP,:ID_CLIENTE,:HORA_ACESSO,:INTERVALO,:TENTATIVA)',
                [
                    ':IP'          => $ip,
                    ':ID_CLIENTE'  => $id,
                    ':HORA_ACESSO' => $horaAtual,
                    ':INTERVALO'   => $interv,
                    ':TENTATIVA'   => $tentativaAtual,
                ]
            );

            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Salva a quantidade de tentativas de acesso
     *
     * @param $tentativas
     * @param $ip
     * @return bool
     */
    public function salvar_qtd_tentativas_ip($tentativas, $ip)
    {
        try {
            $this->bd->executar(
                'UPDATE TBL_IP_ADWORDS SET QTD_TENTATIVAS = :QTD_TENTATIVAS WHERE IP = :IP',
                [
                    ':QTD_TENTATIVAS' => $tentativas,
                    ':IP'             => $ip,
                ]
            );

            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Salva a quantidade de tentativas de acesso.
     *
     * @param $dispositivo
     * @param $ip
     * @return bool
     */
    public function salvar_dispositivo_ip($dispositivo, $ip)
    {
        try {
            /* Conecta com o banco para inserir os dados */
            $this->bd->executar(
                'UPDATE TBL_IP_ADWORDS SET DISPOSITIVO = :DISPOSITIVO WHERE IP = :IP',
                [
                    ':DISPOSITIVO' => $dispositivo,
                    ':IP'          => $ip,
                ]
            );

            return true;
        } catch (Exception $e) {
            return false;
        }
    }
}
