<?php

namespace Softsat\Locacao\Controller;

//require Module::path('email');
//require Module::file('email', 'helpers/smtphelper.php');

use Hwapx\Admin\Controller\Admin\Admin;
use Hwapx\Core\Library\Template;
use Hwapx\Core\Library\Validator;
use HwapX\Admin\Library\Builder\TableBuilder;
use HwapX\Admin\Library\Builder\FormBuilder;
use HwapX\Core\Library\DB\SQL\Mapper;

class Site {
    protected $por_pagina = 6;

    protected $email_rules = array(
        'nome' => array(
            'required',
        ),
        'email' => array(
            'required',
            'email',
        ),
        'assunto' => array(
            'required',
        ),
        'mensagem' => array(
            'required',
        ),
    );
    
    protected $filter_rules = array(
        'local_saida' => array(
            'required',
        ),
        'saida'   => array(
            'required',
            'date',
        ),
        'local_entrada' => array(
            'required',
        ),
        'entrada' => array(
            'required',
            'date',
        ),
        'marca' => array(),
    );
    
    protected $reserve_rules = array(
        'local_saida' => array(
            'required',
        ),
        'saida'   => array(
            'required',
            'date',
        ),
        'local_entrada' => array(
            'required',
        ),
        'entrada' => array(
            'required',
            'date',
        ),
        'veiculo' => array(
            'required',
        ),
    );
    
    protected $reset_rules = array(
        'email'   => array(
            'required',
        ),
        'codigo' => array(
            'required',
        ),
        'senha' => array(
            'required',
            'password',
            'equals' => 'senha_confirmacao',
        ),
        'senha_confirmacao' => array(
            'required',
        ),
    );
    
    protected $account_rules = array(
        'nome' => array(
            'label' => 'Nome',
            'rules' => array(
                'required',
                'lengthMax' => 255,
            ),
        ),
        'nascimento' => array(
            'label' => 'Data de nascimento',
            'rules' => array(
                'required',
                'date',
            ),
        ),
        'cnpj_cpf' => array(
            'label' => 'CNPJ/CPF',
            'rules' => array(
                'required',
                'cnpj_cpf',
                'lengthMax' => 18,
                'regex' => '/^[0-9]{3}\.[0-9]{3}\.[0-9]{3}-[0-9]{2}|[0-9]{2}.[0-9]{3}.[0-9]{3}\/[0-9]{4}-[0-9]{2}$/',
            ),
        ),
        'ie_rg' => array(
            'label' => 'IE/RG',
            'rules' => array(
                'required',
                'lengthMax' => 15,
                'regex' => '/^[0-9]*$/',
            ),
        ),
        'cnh' => array(
            'label' => 'CNH',
            'rules' => array(
                'required',
                'lengthMax' => 20,
                'regex' => '/^[0-9]+$/',
                'cnh',
            ),
        ),
        'endereco' => array(
            'label' => 'Endereço',
            'rules' => array(
                'required',
                'lengthMax' => 255,
            ),
        ),
        'numero' => array(
            'label' => 'Número',
            'rules' => array(
                'lengthMax' => 10,
            ),
        ),
        'bairro' => array(
            'label' => 'Bairro',
            'rules' => array(
                'lengthMax' => 255,
            ),
        ),
        'cidade' => array(
            'label' => 'Cidade',
            'rules' => array(
                'lengthMax' => 255,
            ),
        ),
        'estado' => array(
            'label'   => 'Estado',
            'rules' => array(
                'lengthMax' => 2,
            ),
        ),
        'cep' => array(
            'label' => 'CEP',
            'rules' => array(
                'lengthMax' => 9,
            ),
        ),
        'celular' => array(
            'label' => 'Celular',
            'rules' => array(
                'required',
                'lengthMax' => 15,
            ),
        ),
        'telefone' => array(
            'label' => 'Telefone residencial',
            'rules' => array(
                'lengthMax' => 15,
            ),
        ),
        'telefone_comercial' => array(
            'label' => 'Telefone comercial',
            'rules' => array(
                'lengthMax' => 15,
            ),
        ),
        'email' => array(
            'label' => 'Email',
            'rules' => array(
                'required',
                'email',
                'lengthMax' => 255,
            )
        ),
        'senha' => array(
            'label' => 'Senha',
        ),
        'senha_confirmacao' => array(
            'label' => 'Confirmaçaõ da senha',
        ),
    );

    public function __construct($f3) {
        //parent::__construct($f3);

        if($f3->get('settings.site.manutencao') === 'sim')
            $f3->error(403, 'Em manutenção');
            //$f3->reroute('@manutencao');
    }

    public function index($f3) {
        $db = $f3->get('db');
        
        $email = $f3->get('GET.email');
        
        $redefinir = $email ? array(
                'email'  => $email,
                'codigo' => $f3->get('GET.codigo'),
            ) : null;
        
        $data = array(
            'redefinir' => $redefinir,
            'saida'     => date('Y-m-d'),
            'entrada'   => date('Y-m-d'),
            'cliente'   => $f3->get('SESSION.cliente'),
            'marcas'    => $db->exec('SELECT * FROM softsat_locacao_marca WHERE EXISTS(SELECT 1 FROM softsat_locacao_veiculo WHERE softsat_locacao_veiculo.marca_id = softsat_locacao_marca.id)'),
            'veiculos'  => $this->fetchAvailable($db, date('Y-m-d'), date('Y-m-d'), null, 1),
            'locais'    => $db->exec('SELECT * FROM softsat_locacao_local WHERE ativo = 1'),
        );
        
        echo Template::instance()->render('softsat/locacao/index.html', null, $data);
    }
    
    public function login($f3) {
        if ($f3->get('VERB') !== 'POST') {
            echo Template::instance()->render('softsat/locacao/partials/login.html');
            return;
        }
        
        $db = $f3->get('db');
        $post = array(
            'email' => $f3->get('POST.email'),
            'senha' => $f3->get('POST.senha'),
        );

        $cliente = new \DB\SQL\Mapper($db, 'softsat_locacao_cliente');
        $cliente->load(array('LOWER(email) = LOWER(?)', $post['email']));

        if ($cliente->dry() || !\Bcrypt::instance()->verify($post['senha'], $cliente->senha)) {
            echo json_encode(array(
               'error'   => true,
               'message' => 'Usuário ou senha incorretos',
            ));
            
            return;
        }
        
        $parts = explode(' ', $cliente->nome);

        $data = array(
            'id'    => $cliente->id,
            'email' => $cliente->email,
            'nome'  => $cliente->nome,
            'nick'  => reset($parts),
        );
        
        $f3->set('SESSION.cliente', $data);
        
        echo json_encode(array(
            'error' => false,
            'data'  => $data,
        ));
    }
    
    public function logout($f3) {
        $f3->clear('SESSION.cliente');
        
        $f3->reroute('@softsat_locacao_index');
    }
    
    public function reset($f3) {
        srand();
        
        $code  = '';
        $email = $f3->get('POST.email');
        
        for($i = 0; $i < 32; $i++)
            $code .= rand() % 3 ? rand(0, 9) : chr(rand(65, 90));
            
        $db = $f3->get('db');
        
        $updated = $db->exec('UPDATE softsat_locacao_cliente SET token = ?, token_date = CURRENT_DATE WHERE email = ?', array($code, $email));
        
        echo json_encode(array(
            'error'   => !(bool)$updated,
            'message' => $updated ? 'Link de redefinição enviado.' : 'Email não localizado.',
        ));
        
        if($updated)
            \SMTPEnqueue($f3->get('settings.softsat.locacao.email.redefinir_senha'), array('link' => $f3->alias('softsat_locacao_index') . "?email=$email&codigo=$code"), $email);
    }
    
    public function reset2($f3) {
        $db = $f3->get('db');
        
        $data  = array_intersect_key($f3->get('POST'), $this->reset_rules);
        
        $validator = Validator::createFromRules($this->reset_rules, $data);
        
        if(!$validator->validate()) {
            $erros = $validator->errors();
            echo json_encode(array(
                'error'   => true,
                'message' => isset($erros['senha']) ? $erros['senha'] : 'Paramêtros inválidos, contate o administrador',
            ));
            
            return;
        }
        
        $email = $data['email'];
        $senha = \Bcrypt::instance()->hash($data['senha']);

        $updated = $db->exec('UPDATE softsat_locacao_cliente SET token = NULL, senha = ? WHERE email = ? AND token_date >= CURRENT_DATE - INTERVAL 1 DAY', array($senha, $email));

        echo json_encode(array(
            'error'   => !(bool)$updated,
            'message' => $updated ? 'Senha redefinida.' : 'Código expirado, solicite a redefinição novamente.',
        ));
    }
    
    public function register($f3) {
        $db     = $f3->get('db');
        $mapper = new Mapper($db, 'softsat_locacao_cliente');
        $data   = array();
        
        if ($f3->get('VERB') === 'POST') {
            $post = array_intersect_key($f3->get('POST'), $this->account_rules);
            
            $validator = Validator::createFrom($this->account_rules, $post);
            
            $validator->rule('required', 'senha');
            $validator->rule('required', 'senha_confirmacao');
            $validator->rule('equals', 'senha_confirmacao', 'senha');
            $validator->rule(function($field, $value) use($db) {
                return !$db->exec('SELECT 1 FROM softsat_locacao_cliente WHERE email = ?', array($value));
            }, 'email')->message("{field} já está em uso");
            $validator->rule(function($field, $value) use($db) {
                return !$db->exec('SELECT 1 FROM softsat_locacao_cliente WHERE cnpj_cpf = ?', array($value));
            }, 'cnpj_cpf')->message("{field} já está em uso");
            $validator->rule(function($field, $value) use($db) {
                return !$db->exec('SELECT 1 FROM softsat_locacao_cliente WHERE cnh = ?', array($value));
            }, 'cnh')->message("{field} já está em uso");

            if(isset($post['nascimento'])) {
                $dt =  \DateTime::createFromFormat('d/m/Y', $post['nascimento']);
                if($dt)
                    $post['nascimento'] = $dt->format('Y-m-d');
            }

            $mapper->copyFrom($post);
            
            if($validator->validate()) {
                if($post['senha'])
                    $mapper->senha = \Bcrypt::instance()->hash($post['senha']);

                $mapper->save();
                $data['msg']     = 'Cadastro efetuado com sucesso';
                echo Template::instance()->render('softsat/locacao/partials/registred.html', null, $data);
                return;
            } else {
                $data['erros'] = $validator->errors();
                $data['msg']   = 'Verifique os campos';
            }
        
            $data['cliente'] = $mapper->cast();
        }
        
        echo Template::instance()->render('softsat/locacao/partials/register.html', null, $data);
    }
    
    public function account($f3) {
        $cliente_id = (int)$f3->get('SESSION.cliente.id');
        
        if(!$cliente_id) {
            $f3->error(403);
            return;
        }
        
        $db     = $f3->get('db');
        $mapper = new Mapper($db, 'softsat_locacao_cliente');
        $data   = array();

        if(!$mapper->load(array('id = ?', $cliente_id))) {
            $f3->error(404);
            return;
        }
        
        if ($f3->get('VERB') === 'POST') {
            $post = array_intersect_key($f3->get('POST'), $this->account_rules);

            $validator = Validator::createFrom($this->account_rules, $post);
            
            $validator->rule(function($field, $value) use($db, $cliente_id) {
                return !$db->exec('SELECT 1 FROM softsat_locacao_cliente WHERE email = ? AND id <> ?', array($value, $cliente_id));
            }, 'email')->message("{field} já está em uso");
            $validator->rule(function($field, $value) use($db, $cliente_id) {
                return !$db->exec('SELECT 1 FROM softsat_locacao_cliente WHERE cnpj_cpf = ? AND id <> ?', array($value, $cliente_id));
            }, 'cnpj_cpf')->message("{field} já está em uso");
            $validator->rule(function($field, $value) use($db, $cliente_id) {
                return !$db->exec('SELECT 1 FROM softsat_locacao_cliente WHERE cnh = ? AND id <> ?', array($value, $cliente_id));
            }, 'cnh')->message("{field} já está em uso");
            
            if(!$post['senha'])
                unset($post['senha']);

            if(isset($post['nascimento'])) {
                $dt =  \DateTime::createFromFormat('d/m/Y', $post['nascimento']);
                if($dt)
                    $post['nascimento'] = $dt->format('Y-m-d');
            }

            $mapper->copyFrom($post);
            
            if($validator->validate()) {

                if($post['senha'])
                    $mapper->senha = \Bcrypt::instance()->hash($post['senha']);
                    
                $mapper->save();
                $data['msg']   = 'Dados salvos com sucesso';
                
                $parts = explode(' ', $mapper->nome);
                
                $f3->set('SESSION.cliente.nick', reset($parts));
            } else {
                $data['erros'] = $validator->errors();
                $data['msg']   = 'Verifique os campos';
            }
        }
        
        $data['cliente'] = $mapper->cast();
        
        echo Template::instance()->render('softsat/locacao/partials/account.html', null, $data);
    }
    
    public function history($f3) {
        $cliente_id = (int)$f3->get('SESSION.cliente.id');
        
        if(!$cliente_id) {
            $f3->error(403);
            return;
        }
        
        $db = $f3->get('db');
        
        $data = array(
            'contratos' => $db->exec('SELECT * FROM softsat_locacao_contrato_relatorio WHERE cliente_id = ?', $cliente_id),
        );
        
        echo Template::instance()->render('softsat/locacao/partials/contratos.html', null, $data);
    }
    
    public function reserve($f3) {
        $cliente_id = (int)$f3->get('SESSION.cliente.id');
        
        if(!$cliente_id) {
            echo json_encode(array(
                'error' => true,
                'login' => true,
                'message' => 'Você deve fazer login para poder reservar um veículo.',
            ));
            return;
        }
        
        $data  = array_intersect_key($f3->get('POST'), $this->reserve_rules);
        
        $validator = Validator::createFromRules($this->reserve_rules, $data);
        
        if(!$validator->validate()) {
            echo json_encode(array(
                'error'   => true,
                'message' => 'Paramêtros inválidos.',
                'fields'  => $validator->errors(),
            ));
            return;
        }
        
        $data['saida']   = \DateTime::createFromFormat('d/m/Y H:i:s', $data['saida'])->format('Y-m-d H:i:s');
        $data['entrada'] = \DateTime::createFromFormat('d/m/Y H:i:s', $data['entrada'])->format('Y-m-d H:i:s');

        $db      = $f3->get('db');
        $veiculos = $db->exec('CALL softsat_locacao_veiculo_disponivel(?, ?, NULL, ?)', array($data['saida'], $data['entrada'], $data['veiculo']));

        if(!$veiculos) {
            echo json_encode(array(
                'error'   => true,
                'message' => 'O veículo não está mais disponível.'
            ));
            return;
        }

        $veiculo = $veiculos[0];

        $contrato = new Mapper($db, 'softsat_locacao_contrato');
        $contrato->cliente_id       = $cliente_id;
        $contrato->veiculo_id       = $veiculo['id'];
        $contrato->local_saida_id   = $data['local_saida'];
        $contrato->saida            = $data['saida'];
        $contrato->local_entrada_id = $data['local_entrada'];
        $contrato->previsto         = $data['entrada'];
        $contrato->status           = 'R';
        $contrato->tarifa_id        = $veiculo['tarifa_id'];
        $contrato->diaria           = $veiculo['diaria'];
        $contrato->perc_multa_excedido   = $f3->get('settings.softsat.locacao.contrato.perc_multa_excedido');
        $contrato->indenizacao_carro     = $veiculo['indenizacao_carro'];
        $contrato->indenizacao_terceiros = $veiculo['indenizacao_terceiros'];
        if(!$contrato->save()) {
            echo json_encode(array(
                'error'   => true,
                'message' => 'Falha ao realizar a reserva, entre em contato com o administrador.'
            ));
            return;
        }

        echo json_encode(array(
            'error'   => false,
            'message' => 'Reserva efetuada com sucesso.'
        ));
    }
    
    public function cancel($f3) {
        $cliente_id = (int)$f3->get('SESSION.cliente.id');

        $data = array();
        
        if($cliente_id) {
            $db = $f3->get('db');

            $success = (bool)$db->exec(
                "UPDATE softsat_locacao_contrato SET status = 'C' WHERE id = ? AND cliente_id = ? AND status = 'R'",
                array((int)$f3->get('PARAMS.id'), $cliente_id));

            $data['contratos'] = $db->exec('SELECT * FROM softsat_locacao_contrato_relatorio WHERE cliente_id = ?', $cliente_id);

            if($success)
                $data['success'] = 'Reserva cancelada com sucesso!';
            else
                $data['error'] = 'Não foi possível cancelar a reserva, entre em contato com o administrador.';
        } else {
            $data['error'] = 'Você deve estar logado para executar esta ação.';
        }

        echo Template::instance()->render('softsat/locacao/partials/contratos.html', null, $data);
    }
    
    public function available($f3) {
        $data  = array(
            'params' => array_intersect_key($f3->get('GET'), $this->filter_rules),
        );
        
        $validator = Validator::createFromRules($this->filter_rules, $data['params']);
        
        if(!$validator->validate()) {
            echo json_encode(array(
                'error'   => true,
                'message' => 'Paramêtros inválidos.',
                'fields'  => $validator->errors(),
            ));
            return;
        }
        
        $pagina  = $f3->get('GET.pagina') ?: 1;
        $saida   = \DateTime::createFromFormat('d/m/Y H:i:s', $data['params']['saida'])->format('Y-m-d H:i:s');
        $entrada = \DateTime::createFromFormat('d/m/Y H:i:s', $data['params']['entrada'])->format('Y-m-d H:i:s');
        
        $data['veiculos'] = $this->fetchAvailable($f3->get('db'), $saida, $entrada, $data['params']['marca'], $pagina);

        echo Template::instance()->render('softsat/locacao/partials/veiculos.html', null, $data);
    }
    
    public function contact($f3) {
        $data = array_intersect_key($f3->get('POST'), $this->email_rules);
        $data = array_map(function($v) {
            return htmlentities($v);
        }, $data);

        $validator = Validator::createFromRules($this->email_rules, $data);

        if(!$validator->validate()) {
            echo json_encode(array(
                'error'   => true,
                'message' => 'Dados inválidos',
                'fields'  => $validator->errors()
            ));
            return;
        }

        $success = \SMTPEnqueue($f3->get('settings.softsat.locacao.email.contato'), $data);

        echo json_encode(array(
            'error'   => !$success,
            'message' => $success ? 'Mensagem enviada com sucesso' : 'Falha no envio.',
        ));
    }

    protected function fetchAvailable($db, $saida, $entrada, $marca, $pagina) {
        $veiculos = $db->exec('CALL softsat_locacao_veiculo_disponivel(?, ?, ?, NULL)', array($saida, $entrada, $marca ?: null));

        $offset = $this->por_pagina * ($pagina - 1);

        return array(
            'items'      => array_slice($veiculos, $offset, $this->por_pagina),
            'pagina'     => $pagina,
            'offset'     => $offset,
            'total'      => count($veiculos),
            'paginas'    => ceil(count($veiculos) / $this->por_pagina),
            'por_pagina' => $this->por_pagina,
        );
    }
}
