<?php

namespace App\Http\Controllers;

use App\Models\Cliente;
use App\Models\Cidade;
use App\Models\ConfigGeral;
use App\Models\FaturaCliente;
use App\Models\Nfe;
use App\Models\Nfce;
use App\Models\ItemNfe;
use App\Models\ItemNfce;
use App\Models\ContaReceber;
use App\Models\Fornecedor;
use App\Models\CreditoCliente;
use App\Models\TributacaoCliente;
use App\Models\ListaPrecoUsuario;
use Illuminate\Http\Request;
use App\Imports\ProdutoImport;
use Maatwebsite\Excel\Facades\Excel;
use App\Rules\ValidaDocumentoCliente;
use App\Utils\UploadUtil;

class ClienteController extends Controller
{
    protected $util;
    public function __construct(UploadUtil $util)
    {
        $this->util = $util;
        $this->middleware('permission:clientes_create', ['only' => ['create', 'store']]);
        $this->middleware('permission:clientes_edit', ['only' => ['edit', 'update']]);
        $this->middleware('permission:clientes_view', ['only' => ['show', 'index']]);
        $this->middleware('permission:clientes_delete', ['only' => ['destroy']]);
    }

    private function setNumeroSequencial(){
        $clientes = Cliente::where('empresa_id', request()->empresa_id)
        ->where('numero_sequencial', null)
        ->get();

        $numero = __getUltimoNumeroSequencial(request()->empresa_id, 'clientes');
        // $numero++;

        foreach($clientes as $cliente){
            $numero++;
            $cliente->numero_sequencial = $numero;
            $cliente->save();
        }

        __setUltimoNumeroSequencial(request()->empresa_id, 'clientes', $numero);
    }

    public function modal($id){
        $item = Cliente::findOrFail($id);
        return view('clientes.partials.modal_body', compact('item'))->render();
    }

    public function index(Request $request)
    {
        $this->setNumeroSequencial();

        $start_date = $request->get('start_date');
        $end_date = $request->get('end_date');
        $ordem = $request->get('ordem');
        $valor_credito = $request->get('valor_credito');

        $data = Cliente::where('empresa_id', request()->empresa_id)
        ->when(!empty($request->razao_social), function ($q) use ($request) {
            return  $q->where(function ($quer) use ($request) {
                return $quer->where('razao_social', 'LIKE', "%$request->razao_social%");
            });
        })
        ->when(!empty($request->cpf_cnpj), function ($q) use ($request) {
            return  $q->where(function ($quer) use ($request) {
                return $quer->where('cpf_cnpj', 'LIKE', "%$request->cpf_cnpj%");
            });
        })
        ->when(!empty($start_date), function ($query) use ($start_date) {
            return $query->whereDate('created_at', '>=', $start_date);
        })
        ->when(!empty($end_date), function ($query) use ($end_date) {
            return $query->whereDate('created_at', '<=', $end_date);
        })
        ->when(!$ordem, function ($query) {
            return $query->orderBy('razao_social');
        })
        ->when($ordem, function ($query) use ($ordem) {
            return $query->orderBy($ordem, $ordem == 'created_at' ? 'desc' : 'asc');
        })
        ->when($valor_credito == 1 && trim($valor_credito) !== '', function ($query) use ($valor_credito) {
            return $query->where('valor_credito', '>', '0');
        })
        ->when($valor_credito == 0 && trim($valor_credito) !== '', function ($query) use ($valor_credito) {
            return $query->where('valor_credito', '<=', '0');
        })
        ->paginate(__itensPagina());

        $configGeral = ConfigGeral::where('empresa_id', $request->empresa_id)
        ->first();
        $tipoExibe = $configGeral && $configGeral->clientes_exibe_tabela == 0 
        ? 'card' 
        : 'tabela';
        
        return view('clientes.index', compact('data', 'tipoExibe'));
    }

    public function create()
    {
        $listasPreco = ListaPrecoUsuario::select('lista_precos.*')
        ->join('lista_precos', 'lista_precos.id', '=', 'lista_preco_usuarios.lista_preco_id')
        ->where('lista_preco_usuarios.usuario_id', get_id_user())
        ->get();

        $config = ConfigGeral::where('empresa_id', request()->empresa_id)->first();
        $tiposPagamento = Nfce::tiposPagamento();
        if($config != null){
            $config->tipos_pagamento_pdv = $config != null && $config->tipos_pagamento_pdv ? json_decode($config->tipos_pagamento_pdv) : [];
            $temp = [];
            if(sizeof($config->tipos_pagamento_pdv) > 0){
                foreach($tiposPagamento as $key => $t){
                    if(in_array($t, $config->tipos_pagamento_pdv)){
                        $temp[$key] = $t;
                    }
                }
                $tiposPagamento = $temp;
            }
        }

        return view('clientes.create', compact('listasPreco', 'tiposPagamento'));
    }

    public function edit($id)
    {
        $item = Cliente::findOrFail($id);
        __validaObjetoEmpresa($item);

        $listasPreco = ListaPrecoUsuario::select('lista_precos.*')
        ->join('lista_precos', 'lista_precos.id', '=', 'lista_preco_usuarios.lista_preco_id')
        ->where('lista_preco_usuarios.usuario_id', get_id_user())
        ->get();

        $config = ConfigGeral::where('empresa_id', request()->empresa_id)->first();
        $tiposPagamento = Nfce::tiposPagamento();
        if($config != null){
            $config->tipos_pagamento_pdv = $config != null && $config->tipos_pagamento_pdv ? json_decode($config->tipos_pagamento_pdv) : [];
            $temp = [];
            if(sizeof($config->tipos_pagamento_pdv) > 0){
                foreach($tiposPagamento as $key => $t){
                    if(in_array($t, $config->tipos_pagamento_pdv)){
                        $temp[$key] = $t;
                    }
                }
                $tiposPagamento = $temp;
            }
        }

        return view('clientes.edit', compact('item', 'listasPreco', 'tiposPagamento'));
    }

    public function store(Request $request)
    {
        // $this->__validate($request);
        try {

            $file_name = '';
            if ($request->hasFile('image')) {
                $file_name = $this->util->uploadImage($request, '/clientes');
            }

            $request->merge([
                'ie' => $request->ie ?? '',
                'nome_fantasia' => $request->nome_fantasia ?? '',
                'valor_cashback' => $request->valor_cashback ? __convert_value_bd($request->valor_cashback) : 0,
                'valor_credito' => $request->valor_credito ? __convert_value_bd($request->valor_credito) : 0,
                'imagem' => $file_name,
            ]);

            $cliente = Cliente::where('empresa_id', $request->empresa_id)
            ->where('cpf_cnpj', $request->cpf_cnpj)
            ->first();

            // if($cliente){
            //     session()->flash("flash_error", "Cliente já esta cadastrado");
            // }
            $cliente = Cliente::create($request->all());
            __setUltimoNumeroSequencial(request()->empresa_id, 'clientes', $request->numero_sequencial);

            $this->cadastraTributacao($cliente, $request);

            if($request->insere_fornecedor){
                $numero = __getUltimoNumeroSequencial(request()->empresa_id, 'fornecedors');
                $request->merge([
                    'numero_sequencial' => $numero+1
                ]);
                Fornecedor::create($request->all());
                __setUltimoNumeroSequencial(request()->empresa_id, 'fornecedors', $numero+1);
            }

            if($request->dias_vencimento[0] != ''){
                for($i=0; $i<sizeof($request->dias_vencimento); $i++){
                    FaturaCliente::create([
                        'cliente_id' => $cliente->id,
                        'tipo_pagamento' => $request->tipo_pagamento[$i] ?? null,
                        'dias_vencimento' => $request->dias_vencimento[$i]
                    ]);
                }
            }

            __createLog($request->empresa_id, 'Cliente', 'cadastrar', $request->razao_social);
            session()->flash("flash_success", "Cliente cadastrado!");
        } catch (\Exception $e) {
            // echo $e->getMessage();
            // die;
            __createLog($request->empresa_id, 'Cliente', 'erro', $e->getMessage());
            session()->flash("flash_error", "Algo deu errado: " . $e->getMessage());
        }
        return redirect()->route('clientes.index');
    }

    private function cadastraTributacao($cliente, Request $request){
        if($cliente->tributacao){
            $cliente->tributacao()->delete();
        }

        $request->merge([
            'cliente_id' => $cliente->id
        ]);

        TributacaoCliente::create($request->all());
    }

    public function removeImagem($id){
        $item = Cliente::findOrFail($id);
        try{
            $this->util->unlinkImage($item, '/clientes');
            $item->imagem = '';
            $item->save();
            session()->flash("flash_success", "Imagem removida");
        } catch (\Exception $e) {
            session()->flash("flash_error", "Algo deu errado: " . $e->getMessage());
        }
        return redirect()->back();
    }

    public function update(Request $request, $id)
    {
        $this->__validate($request, $id);
        $item = Cliente::findOrFail($id);
        try {

            $file_name = $item->imagem;

            if ($request->hasFile('image')) {
                $this->util->unlinkImage($item, '/clientes');
                $file_name = $this->util->uploadImage($request, '/clientes');
            }
            $request->merge([
                'ie' => $request->ie ?? '',
                'valor_cashback' => $request->valor_cashback ? __convert_value_bd($request->valor_cashback) : 0,
                'valor_credito' => $request->valor_credito ? __convert_value_bd($request->valor_credito) : 0,
                'imagem' => $file_name,
            ]);
            $item->fill($request->all())->save();

            $this->cadastraTributacao($item, $request);


            if($request->dias_vencimento[0] != ''){
                $item->fatura()->delete();
                for($i=0; $i<sizeof($request->dias_vencimento); $i++){
                    FaturaCliente::create([
                        'cliente_id' => $item->id,
                        'tipo_pagamento' => $request->tipo_pagamento[$i] ?? null,
                        'dias_vencimento' => $request->dias_vencimento[$i]
                    ]);
                }
            }

            __createLog($request->empresa_id, 'Cliente', 'editar', $request->razao_social);
            session()->flash("flash_success", "Cliente atualizado!");
        } catch (\Exception $e) {
            __createLog($request->empresa_id, 'Cliente', 'erro', $e->getMessage());
            session()->flash("flash_error", "Algo deu errado: " . $e->getMessage());
        }
        return redirect()->route('clientes.index');
    }

    private function __validate(Request $request, $id = null)
    {
        $rules = [
            'razao_social' => 'required',
            'cpf_cnpj' => $id == null ? [ 'required', new ValidaDocumentoCliente($request->empresa_id) ] : 'required',
            // 'ie' => 'required',
            'telefone' => 'required',
            'cidade_id' => 'required',
            'rua' => 'required',
            'cep' => 'required',
            'numero' => 'required',
            'bairro' => 'required',
        ];

        $messages = [
            'razao_social.required' => 'Campo Obrigatório',
            'cpf_cnpj.required' => 'Campo Obrigatório',
            'ie.required' => 'Campo Obrigatório',
            'telefone.required' => 'Campo Obrigatório',
            'cidade_id.required' => 'Campo Obrigatório',
            'rua.required' => 'Campo Obrigatório',
            'cep.required' => 'Campo Obrigatório',
            'numero.required' => 'Campo Obrigatório',
            'bairro.required' => 'Campo Obrigatório',
        ];
        $this->validate($request, $rules, $messages);
    }

    public function historico($id)
    {
        $item = Cliente::findOrFail($id);
        __validaObjetoEmpresa($item);

        $nves = Nfe::where('cliente_id', $id)->get();
        $nfces = Nfce::where('cliente_id', $id)->get();

        $data = [];
        foreach($nves as $n){
            $n->tipo = 'nfe';
            array_push($data, $n);
        }

        foreach($nfces as $n){
            $n->tipo = 'nfce';
            array_push($data, $n);
        }

        usort($data, function($a, $b){
            return $a->created_at < $b->created_at ? 1 : -1;
        });

        $produtos = $this->getProdutos($id);
        $faturas = $this->getFaturas($id);

        return view('clientes.historico', compact('item', 'data', 'produtos', 'faturas'));
    }

    private function getProdutos($id){

        $data = [];
        $dataIds = [];

        $itens = ItemNfe::select('item_nves.*')
        ->join('nves', 'nves.id', '=', 'item_nves.nfe_id')
        ->where('nves.cliente_id', $id)
        ->get();

        foreach($itens as $i){
            if(!in_array($i->produto_id, $dataIds)){
                $data[] = $i;
                $dataIds[] = $i->produto_id;
            }else{
                for($j=0; $j<sizeof($data); $j++){
                    if($data[$j]['produto_id'] == $i->produto_id){
                        $data[$j]['quantidade'] += $i->quantidade;
                    }
                }
            }
        }

        $itens = ItemNfce::select('item_nfces.*')
        ->join('nfces', 'nfces.id', '=', 'item_nfces.nfce_id')
        ->where('nfces.cliente_id', $id)
        ->get();

        foreach($itens as $i){
            if(!in_array($i->produto_id, $dataIds)){
                $data[] = $i;
                $dataIds[] = $i->produto_id;
            }else{
                for($j=0; $j<sizeof($data); $j++){
                    if($data[$j]['produto_id'] == $i->produto_id){
                        $data[$j]['quantidade'] += $i->quantidade;
                    }
                }
            }
        }
        // dd($data);
        return $data;
    }

    private function getFaturas($id){
        return ContaReceber::where('cliente_id', $id)
        ->orderBy('id', 'desc')
        ->get();
    }

    public function destroy($id)
    {
        $item = Cliente::findOrFail($id);

        if(sizeof($item->vendas) > 0){
            session()->flash("flash_warning", "Não é possível remover um cliente com vendas!");
            return redirect()->back();
        }
        __validaObjetoEmpresa($item);
        
        $item->tributacao()->delete();
        try {
            $descricaoLog = $item->razao_social;

            $item->delete();
            __createLog(request()->empresa_id, 'Cliente', 'excluir', $descricaoLog);
            session()->flash("flash_success", "Cliente removido!");
        } catch (\Exception $e) {
            __createLog(request()->empresa_id, 'Cliente', 'erro', $e->getMessage());
            session()->flash("flash_error", "Algo deu Errado: " . $e->getMessage());
        }
        return redirect()->back();
    }

    public function import(){
        return view('clientes.import');
    }

    public function downloadModelo(){
        return response()->download(public_path('files/') . 'import_clients_csv_template.xlsx');
    }

    public function storeModelo(Request $request){
        if ($request->hasFile('file')) {
            ini_set('max_execution_time', 0);
            ini_set('memory_limit', -1);

            $rows = Excel::toArray(new ProdutoImport, $request->file);
            $retornoErro = $this->validaArquivo($rows);
            $cont = 0;
            if($retornoErro == ""){
                foreach($rows as $row){
                    foreach($row as $key => $r){

                        if($r[0] != 'RAZÃO SOCIAL' && isset($r[0])){
                            try{
                                $data = $this->preparaObjeto($r, $request->empresa_id);
                                $item = Cliente::create($data);
                                $cont++;
                            }catch(\Exception $e){
                                session()->flash('flash_error', $e->getMessage());
                            }
                        }
                    }
                }

                session()->flash('flash_success', 'Total de clientes importados: ' . $cont);
                return redirect()->back();
            }else{
                session()->flash('flash_error', $retornoErro);
                return redirect()->back();
            }

        }else{
            session()->flash('flash_error', 'Nenhum Arquivo!!');
            return redirect()->back();
        }
    }

    private function preparaObjeto($linha, $empresa_id){
        $cpf_cnpj = trim((string)$linha[2]);
        $mask = '##.###.###/####-##';

        if(strlen($cpf_cnpj) == 11){
            $mask = '###.###.###.##';
        }
        if(!str_contains($cpf_cnpj, ".")){
            $cpf_cnpj = __mask($cpf_cnpj, $mask);
        }

        $cidade = Cidade::where('nome', $linha[7])
        ->where('uf', $linha[8])->first();
        $data = [
            'empresa_id' => $empresa_id,
            'razao_social' => $linha[0],
            'nome_fantasia' => $linha[1] != '' ? $linha[1] : '',
            'cpf_cnpj' => $cpf_cnpj,
            'ie' => $linha[3] != '' ? $linha[3] : '',
            'contribuinte' => $linha[13] != '' ? $linha[13] : 0,
            'consumidor_final' => $linha[14] != '' ? $linha[14] : 0,
            'email' => $linha[10] != '' ? $linha[10] : '',
            'telefone' => $linha[9] != '' ? $linha[9] : '',
            'cidade_id' => $cidade != null ? $cidade->id : 1,
            'rua' => $linha[4],
            'cep' => $linha[11],
            'numero' => $linha[5],
            'bairro' => $linha[6],
            'complemento' => $linha[12] != '' ? $linha[12] : ''
        ];

        return $data;
    }

    private function validaArquivo($rows){
        $cont = 1;
        $msgErro = "";
        foreach($rows as $row){
            foreach($row as $key => $r){
                if(isset($r[0])){
                    $razaoSocial = $r[0];
                    $cpfCnpj = $r[2];
                    $rua = $r[4];
                    $numero = $r[5];
                    $bairro = $r[6];
                    $cidade = $r[7];
                    $uf = $r[8];
                    $cep = $r[11];

                    if(strlen($razaoSocial) == 0){
                        $msgErro .= "Coluna razão social em branco na linha: $cont | "; 
                    }

                    if(strlen($cpfCnpj) == 0){
                        $msgErro .= "Coluna CPF/CNPJ em branco na linha: $cont | "; 
                    }

                    if(strlen($rua) == 0){
                        $msgErro .= "Coluna rua em branco na linha: $cont | "; 
                    }

                    if(strlen($numero) == 0){
                        $msgErro .= "Coluna numero em branco na linha: $cont | "; 
                    }
                    if(strlen($bairro) == 0){
                        $msgErro .= "Coluna bairro em branco na linha: $cont | "; 
                    }
                    if(strlen($cidade) == 0){
                        $msgErro .= "Coluna cidade em branco na linha: $cont | "; 
                    }
                    if(strlen($cep) == 0){
                        $msgErro .= "Coluna CEP em branco na linha: $cont | "; 
                    }

                    if($msgErro != ""){
                        return $msgErro;
                    }
                    $cont++;
                }
            }
        }

        return $msgErro;
    }

    public function alterarStatusCredito(Request $request)
    {
        $credito = CreditoCliente::find($request->id);

        if (!$credito) {
            return response()->json(['status' => false, 'msg' => 'Crédito não encontrado']);
        }

        $credito->status = false;
        $credito->save();

        return response()->json($credito, 200);
    }


    public function cashBack($id){
        $item = Cliente::findOrFail($id);
        return view('clientes.cash_back', compact('item'));
    }

    public function destroySelecet(Request $request)
    {
        $removidos = 0;
        for($i=0; $i<sizeof($request->item_delete); $i++){
            $item = Cliente::findOrFail($request->item_delete[$i]);
            if(sizeof($item->vendas) > 0){
                session()->flash("flash_warning", "Não é possível remover um cliente com vendas!");
                return redirect()->back();
            }
            try {
                $descricaoLog = $item->razao_social;
                $item->enderecosEcommerce()->delete();
                $item->delete();
                $removidos++;
                __createLog(request()->empresa_id, 'Cliente', 'excluir', $descricaoLog);
            } catch (\Exception $e) {
                __createLog(request()->empresa_id, 'Cliente', 'erro', $e->getMessage());
                session()->flash("flash_error", 'Algo deu errado: '. $e->getMessage());
                return redirect()->route('clientes.index');
            }
        }

        session()->flash("flash_success", "Total de itens removidos: $removidos!");
        return redirect()->back();
    }

    public function incompleto(Request $request){
        $empresaId = $request->empresa_id;
        $filtro = $request->get('missing');

        $isBlank = fn($col) => "( {$col} IS NULL OR TRIM({$col}) = '' )";

        $totais = Cliente::query()
        ->where('empresa_id', $empresaId)
        ->selectRaw("SUM(CASE WHEN {$isBlank('razao_social')} THEN 1 ELSE 0 END) as razao_social")
        ->selectRaw("SUM(CASE WHEN {$isBlank('nome_fantasia')} THEN 1 ELSE 0 END) as nome_fantasia")
        ->selectRaw("SUM(CASE WHEN {$isBlank('cpf_cnpj')} THEN 1 ELSE 0 END) as cpf_cnpj")
        ->selectRaw("SUM(CASE WHEN {$isBlank('email')} THEN 1 ELSE 0 END) as email")
        ->selectRaw("SUM(CASE WHEN {$isBlank('telefone')} THEN 1 ELSE 0 END) as telefone")
        ->selectRaw("SUM(CASE WHEN cidade_id IS NULL THEN 1 ELSE 0 END) as cidade_id")
        ->selectRaw("SUM(CASE WHEN {$isBlank('rua')} THEN 1 ELSE 0 END) as rua")
        ->selectRaw("SUM(CASE WHEN {$isBlank('cep')} THEN 1 ELSE 0 END) as cep")
        ->selectRaw("SUM(CASE WHEN {$isBlank('numero')} THEN 1 ELSE 0 END) as numero")
        ->selectRaw("SUM(CASE WHEN {$isBlank('bairro')} THEN 1 ELSE 0 END) as bairro")
        ->first();

        $base = Cliente::where('empresa_id', $empresaId)
        ->where(function ($q) use ($isBlank) {
            $q->whereRaw($isBlank('razao_social'))
            ->orWhereRaw($isBlank('nome_fantasia'))
            ->orWhereRaw($isBlank('cpf_cnpj'))
            ->orWhereRaw($isBlank('email'))
            ->orWhereRaw($isBlank('telefone'))
            ->orWhereNull('cidade_id')
            ->orWhereRaw($isBlank('rua'))
            ->orWhereRaw($isBlank('cep'))
            ->orWhereRaw($isBlank('numero'))
            ->orWhereRaw($isBlank('bairro'));
        });

        if ($filtro) {
            $base->where(function ($q) use ($filtro, $isBlank) {
                switch ($filtro) {
                    case 'cidade_id': $q->whereNull('cidade_id'); break;
                    case 'razao_social':
                    case 'nome_fantasia':
                    case 'cpf_cnpj':
                    case 'email':
                    case 'telefone':
                    case 'rua':
                    case 'cep':
                    case 'numero':
                    case 'bairro':
                    $q->whereRaw($isBlank($filtro));
                    break;
                }
            });
        }

        $clientes = $base->orderByDesc('created_at')->paginate(25)->withQueryString();

        if ($request->ajax()) {
            return view('clientes.partials.tabela_incompletos', compact('clientes'))->render();
        }
        return view('clientes.incompletos', compact('clientes', 'totais', 'filtro'));
    }

}
