<?php
/**
 * This file is part of AgentesComerciales plugin for FacturaScripts
 * Copyright (C) 2025 Your Company <your@email.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

namespace FacturaScripts\Plugins\AgentesComerciales\Controller;

use FacturaScripts\Core\Base\DataBase\DataBaseWhere;
use FacturaScripts\Core\DataSrc\Almacenes;
use FacturaScripts\Core\DataSrc\Empresas;
use FacturaScripts\Core\DataSrc\FormasPago;
use FacturaScripts\Core\DataSrc\Series;
use FacturaScripts\Core\Lib\ExtendedController\ListController;

/**
 * Controller to list invoices from AgentesComerciales plugin
 *
 * @author Your Name <your@email.com>
 */
class ListFacturaCliente extends ListController
{
    public function getPageData(): array
    {
        $data = parent::getPageData();
        $data['menu'] = 'Agentes';
        $data['title'] = 'customer-invoices';
        $data['icon'] = 'fa-solid fa-file-invoice';
        return $data;
    }

    protected function createViews()
    {
        $this->createViewInvoices();
        $this->createViewReceipts();
    }

    protected function createViewInvoices(string $viewName = 'ListFacturaCliente'): void
    {
        $agents = $this->codeModel->all('agentes', 'codagente', 'nombre');
        $users = $this->codeModel->all('users', 'nick', 'nick');
        $companies = Empresas::codeModel();
        $series = Series::codeModel();
        $paymentMethods = FormasPago::codeModel();
        $warehouses = Almacenes::codeModel();

        // Estados de factura
        $statuses = [
            ['code' => '0', 'description' => $this->toolBox()->i18n()->trans('unpaid')],
            ['code' => '1', 'description' => $this->toolBox()->i18n()->trans('paid')],
            ['code' => '2', 'description' => $this->toolBox()->i18n()->trans('partial-paid')]
        ];

        $this->addView($viewName, 'FacturaCliente', 'invoices', 'fa-solid fa-file-invoice')
            ->addOrderBy(['fecha', 'hora'], 'date', 2)
            ->addOrderBy(['codigo'], 'code')
            ->addOrderBy(['numero'], 'number')
            ->addOrderBy(['total'], 'amount')
            ->addOrderBy(['nombre'], 'customer')
            ->addSearchFields(['codigo', 'numero', 'numproveedor', 'nombre', 'observaciones'])
            ->addFilterPeriod('fecha', 'date', 'fecha')
            ->addFilterSelect('idempresa', 'company', 'idempresa', $companies)
            ->addFilterSelect('codserie', 'serie', 'codserie', $series)
            ->addFilterSelect('codalmacen', 'warehouse', 'codalmacen', $warehouses)
            ->addFilterAutocomplete('codcliente', 'customer', 'codcliente', 'clientes', 'codcliente', 'nombre')
            ->addFilterSelect('codagente', 'agent', 'codagente', $agents)
            ->addFilterSelect('nick', 'user', 'nick', $users)
            ->addFilterSelect('codpago', 'payment-method', 'codpago', $paymentMethods)
            ->addFilterSelect('pagada', 'paid', 'pagada', $statuses)
            ->addFilterNumber('totalgt', 'amount', 'total', '>=')
            ->addFilterNumber('totallt', 'amount', 'total', '<=')
            ->setSettings('btnNew', false);

        // Botón personalizado para generar recibos
        $this->addButton($viewName, [
            'action' => 'generate-receipts',
            'color' => 'success',
            'icon' => 'fa-solid fa-plus',
            'label' => 'generate-receipts',
            'type' => 'action'
        ]);

        // Colores por estado
        $this->views[$viewName]->getRow('status')->options[] = [
            'tag' => 'option',
            'children' => [],
            'color' => 'danger',
            'fieldname' => 'pagada',
            'text' => '0',
            'title' => $this->toolBox()->i18n()->trans('unpaid')
        ];
        $this->views[$viewName]->getRow('status')->options[] = [
            'tag' => 'option',
            'children' => [],
            'color' => 'success',
            'fieldname' => 'pagada',
            'text' => '1',
            'title' => $this->toolBox()->i18n()->trans('paid')
        ];
        $this->views[$viewName]->getRow('status')->options[] = [
            'tag' => 'option',
            'children' => [],
            'color' => 'warning',
            'fieldname' => 'pagada',
            'text' => '2',
            'title' => $this->toolBox()->i18n()->trans('partial-paid')
        ];
    }

    protected function createViewReceipts(string $viewName = 'ListReciboCliente'): void
    {
        $agents = $this->codeModel->all('agentes', 'codagente', 'nombre');
        $users = $this->codeModel->all('users', 'nick', 'nick');
        $companies = Empresas::codeModel();
        $paymentMethods = FormasPago::codeModel();

        // Estados de recibo
        $statuses = [
            ['code' => '0', 'description' => $this->toolBox()->i18n()->trans('unpaid')],
            ['code' => '1', 'description' => $this->toolBox()->i18n()->trans('paid')],
            ['code' => '2', 'description' => $this->toolBox()->i18n()->trans('partial-paid')]
        ];

        $this->addView($viewName, 'ReciboCliente', 'receipts', 'fa-solid fa-dollar-sign')
            ->addOrderBy(['fecha'], 'issue-date', 2)
            ->addOrderBy(['vencimiento'], 'expiration')
            ->addOrderBy(['numero'], 'number')
            ->addOrderBy(['importe'], 'amount')
            ->addOrderBy(['codcliente'], 'customer')
            ->addSearchFields(['numero', 'codigofactura', 'codcliente', 'observaciones'])
            ->addFilterPeriod('fecha', 'issue-date', 'fecha')
            ->addFilterPeriod('vencimiento', 'expiration', 'vencimiento')
            ->addFilterSelect('idempresa', 'company', 'idempresa', $companies)
            ->addFilterAutocomplete('codcliente', 'customer', 'codcliente', 'clientes', 'codcliente', 'nombre')
            ->addFilterSelect('nick', 'user', 'nick', $users)
            ->addFilterSelect('codpago', 'payment-method', 'codpago', $paymentMethods)
            ->addFilterSelect('pagado', 'paid', 'pagado', $statuses)
            ->addFilterNumber('importegt', 'amount', 'importe', '>=')
            ->addFilterNumber('importelt', 'amount', 'importe', '<=');

        // Colores por estado de pago
        $this->views[$viewName]->getRow('status')->options[] = [
            'tag' => 'option',
            'children' => [],
            'color' => 'danger',
            'fieldname' => 'pagado',
            'text' => '0',
            'title' => $this->toolBox()->i18n()->trans('unpaid')
        ];
        $this->views[$viewName]->getRow('status')->options[] = [
            'tag' => 'option',
            'children' => [],
            'color' => 'success',
            'fieldname' => 'pagado',
            'text' => '1',
            'title' => $this->toolBox()->i18n()->trans('paid')
        ];
        $this->views[$viewName]->getRow('status')->options[] = [
            'tag' => 'option',
            'children' => [],
            'color' => 'warning',
            'fieldname' => 'pagado',
            'text' => '2',
            'title' => $this->toolBox()->i18n()->trans('partial-paid')
        ];
    }

    protected function loadData($viewName, $view)
    {
        switch ($viewName) {
            case 'ListFacturaCliente':
                $view->loadData();
                break;

            case 'ListReciboCliente':
                $view->loadData();
                break;
        }
    }

    protected function execPreviousAction($action)
    {
        switch ($action) {
            case 'generate-receipts':
                $this->generateReceiptsAction();
                return true;

            default:
                return parent::execPreviousAction($action);
        }
    }

    protected function generateReceiptsAction(): void
    {
        $selectedCodes = $this->request->request->get('code', []);
        if (empty($selectedCodes)) {
            $this->toolBox()->i18nLog()->error('no-invoices-selected');
            return;
        }

        $generados = 0;
        $facturaModel = new \FacturaScripts\Dinamic\Model\FacturaCliente();
        
        foreach ($selectedCodes as $code) {
            if (!$facturaModel->loadFromCode($code)) {
                continue;
            }

            $recibosExistentes = $facturaModel->getReceipts();
            if (count($recibosExistentes) !== 1) {
                continue;
            }

            $formaPago = new \FacturaScripts\Dinamic\Model\FormaPago();
            $requiereFraccionamiento = false;
            
            if ($formaPago->loadFromCode($facturaModel->codpago)) {
                $descripcion = strtolower($formaPago->descripcion);
                $requiereFraccionamiento = (strpos($descripcion, '30,60,90') !== false || 
                                          strpos($descripcion, '30-60-90') !== false);
            }

            if ($requiereFraccionamiento) {
                foreach ($recibosExistentes as $reciboExistente) {
                    $reciboExistente->delete();
                }
                
                $recibosCreados = $this->crearRecibosFraccionados($facturaModel);
                $this->toolBox()->i18nLog()->info('DEBUG: Recibos creados: ' . $recibosCreados);
                $generados += $recibosCreados;
                
                // Generar asiento de traspaso para esta factura
                if ($recibosCreados === 3) {
                    $this->toolBox()->i18nLog()->info('DEBUG: Entrando en asiento traspaso');
                    $this->generarAsientoTraspaso($facturaModel);
                }
            } else {
                continue;
            }
        }

        if ($generados > 0) {
            $this->toolBox()->i18nLog()->info('receipts-generated-correctly', ['%num%' => $generados]);
        } else {
            $this->toolBox()->i18nLog()->warning('no-receipts-to-generate');
        }
    }

    private function crearRecibosFraccionados($factura): int
    {
        $diasVencimiento = [30, 60, 90];
        $importeRecibo = round($factura->total / 3, 2);
        $importeUltimo = $factura->total - ($importeRecibo * 2);
        
        $recibosCreados = 0;
        
        foreach ($diasVencimiento as $index => $dias) {
            $recibo = new \FacturaScripts\Dinamic\Model\ReciboCliente();
            
            $recibo->codcliente = $factura->codcliente;
            $recibo->coddivisa = $factura->coddivisa;
            $recibo->codigofactura = $factura->codigo;
            $recibo->codpago = $factura->codpago;
            $recibo->fecha = $factura->fecha;
            $recibo->idempresa = $factura->idempresa;
            $recibo->idfactura = $factura->idfactura;
            $recibo->nick = $factura->nick;
            
            $recibo->importe = ($index === 2) ? $importeUltimo : $importeRecibo;
            
            $fechaVencimiento = new \DateTime($factura->fecha);
            $fechaVencimiento->add(new \DateInterval("P{$dias}D"));
            $recibo->vencimiento = $fechaVencimiento->format('Y-m-d');
            
            $recibo->numero = $this->getNextReciboNumber($factura->idempresa);
            
            $recibo->pagado = false;
            $recibo->vencido = false;
            $recibo->liquidado = 0;
            $recibo->gastos = 0;
            
            $recibo->observaciones = "Recibo " . ($index + 1) . "/3 - Vencimiento a {$dias} días de la Factura {$factura->codigo} de Fecha {$factura->fecha}";

            if ($recibo->save()) {
                $recibosCreados++;
            }
        }
        
        return $recibosCreados;
    }

    private function generarAsientoTraspaso($factura): void
    {
        $subcuentaCliente = $this->obtenerSubcuentaCliente($factura);
        if (!$subcuentaCliente) {
            $this->toolBox()->i18nLog()->info('DEBUG: No se encontró subcuenta cliente');
            return;
        }
         $this->toolBox()->i18nLog()->info('DEBUG: Subcuenta cliente encontrada: ' . $subcuentaCliente->codsubcuenta);

        $subcuentaEfectos = $this->crearSubcuentaEfectos($subcuentaCliente);
        if (!$subcuentaEfectos) {
            return;
        }

        $asiento = new \FacturaScripts\Dinamic\Model\Asiento();
        $asiento->codejercicio = $factura->codejercicio;
        $asiento->concepto = "Traspaso recibos fraccionados - Factura " . $factura->codigo;
        $asiento->documento = $factura->codigo;
        $asiento->fecha = $factura->fecha;
        $asiento->idempresa = $factura->idempresa;
        $asiento->importe = $factura->total;
        $asiento->editable = true;

        if (!$asiento->save()) {
            return;
        }

        $this->crearLineaAsiento($asiento, $subcuentaEfectos, $factura->total, 0);
        $this->crearLineaAsiento($asiento, $subcuentaCliente, 0, $factura->total);
    }

    private function obtenerSubcuentaCliente($factura): ?object
    {
        if (empty($factura->cifnif)) {
            return null;
        }
        
        $ultimosDigitos = $this->extraerUltimos4Digitos($factura->cifnif);
        $codigoSubcuenta = '430000' . $ultimosDigitos;
        
        $subcuenta = new \FacturaScripts\Dinamic\Model\Subcuenta();
        $where = [
            new \FacturaScripts\Core\Base\DataBase\DataBaseWhere('codsubcuenta', $codigoSubcuenta),
            new \FacturaScripts\Core\Base\DataBase\DataBaseWhere('codejercicio', $factura->codejercicio)
        ];
        
        $subcuentas = $subcuenta->all($where, [], 0, 1);
        return empty($subcuentas) ? null : $subcuentas[0];
    }

    private function extraerUltimos4Digitos($cifnif): string
    {
        $soloNumeros = preg_replace('/[^0-9]/', '', $cifnif);
        return str_pad(substr($soloNumeros, -4), 4, '0', STR_PAD_LEFT);
    }

    private function crearSubcuentaEfectos($subcuentaCliente): ?object
    {
        $codigoEfectos = str_replace('4300', '4310', $subcuentaCliente->codsubcuenta);
        
        $subcuentaExistente = new \FacturaScripts\Dinamic\Model\Subcuenta();
        $where = [
            new \FacturaScripts\Core\Base\DataBase\DataBaseWhere('codsubcuenta', $codigoEfectos),
            new \FacturaScripts\Core\Base\DataBase\DataBaseWhere('codejercicio', $subcuentaCliente->codejercicio)
        ];
        
        $subcuentas = $subcuentaExistente->all($where, [], 0, 1);
        if (!empty($subcuentas)) {
            return $subcuentas[0];
        }
        
        // Buscar o crear cuenta padre 431
        $cuenta431 = new \FacturaScripts\Dinamic\Model\Cuenta();
        $whereCuenta = [
            new \FacturaScripts\Core\Base\DataBase\DataBaseWhere('codcuenta', '431'),
            new \FacturaScripts\Core\Base\DataBase\DataBaseWhere('codejercicio', $subcuentaCliente->codejercicio)
        ];
        $cuentas431 = $cuenta431->all($whereCuenta, [], 0, 1);
        
        if (empty($cuentas431)) {
            // Crear cuenta 431
            $cuenta431 = new \FacturaScripts\Dinamic\Model\Cuenta();
            $cuenta431->codcuenta = '431';
            $cuenta431->descripcion = 'Efectos a cobrar';
            $cuenta431->codejercicio = $subcuentaCliente->codejercicio;
            
            if (!$cuenta431->save()) {
                return null;
            }
        } else {
            $cuenta431 = $cuentas431[0];
        }
        
        $nuevaSubcuenta = new \FacturaScripts\Dinamic\Model\Subcuenta();
        $nuevaSubcuenta->codsubcuenta = $codigoEfectos;
        $nuevaSubcuenta->descripcion = str_replace('430', '431 - Efectos a cobrar', $subcuentaCliente->descripcion);
        $nuevaSubcuenta->codcuenta = '431';
        $nuevaSubcuenta->codejercicio = $subcuentaCliente->codejercicio;
        $nuevaSubcuenta->idcuenta = $cuenta431->idcuenta;
        
        return $nuevaSubcuenta->save() ? $nuevaSubcuenta : null;
    }

    private function crearLineaAsiento($asiento, $subcuenta, $debe, $haber): void
    {
        $partida = new \FacturaScripts\Dinamic\Model\Partida();
        $partida->idasiento = $asiento->idasiento;
        $partida->codsubcuenta = $subcuenta->codsubcuenta;
        $partida->idsubcuenta = $subcuenta->idsubcuenta;
        $partida->concepto = $asiento->concepto;
        $partida->debe = $debe;
        $partida->haber = $haber;
        $partida->save();
    }

    protected function getNextReciboNumber(int $idempresa): int
    {
        $recibo = new \FacturaScripts\Dinamic\Model\ReciboCliente();
        $sql = "SELECT COALESCE(MAX(numero), 0) + 1 as siguiente FROM " . $recibo->tableName() 
             . " WHERE idempresa = " . $idempresa;
             
        $data = $this->dataBase->select($sql);
        return empty($data) ? 1 : (int) $data[0]['siguiente'];
    }
}