<?php

namespace App\Controllers\Crm;

use App\Controllers\BaseController;
use App\Models\Contacts\ContactsModel;
use App\Models\Quotes\QuotesModel;
use App\Models\Quotes\QuoteServicesModel;
use App\Models\Quotes\QuoteListModel;
use App\Models\Companies\CompaniesModel;

use Dompdf\Dompdf;
use Dompdf\Options;

class QuotesController extends BaseController
{
    protected QuotesModel $quoteModel;
    protected QuoteListModel $quoteListModel;

    public function __construct()
    {
        $this->quoteModel = new QuotesModel();
        $this->quoteListModel = new QuoteListModel();
    }

    public function index()
    {
        $quotes = $this->quoteListModel
            ->orderBy('PK_Quote', 'DESC')
            ->findAll();

        return view('crm/quotes/index', compact('quotes'));
    }

    public function delete($id)
    {
        $quote = $this->quoteModel->find($id);

        // if (!$quote || $quote['Status'] !== 'Cotizacion') {
        //     return redirect()->back()
        //         ->with('error', 'No se puede eliminar esta cotización');
        // }

        $this->quoteModel->delete($id);

        return redirect()->back()
            ->with('success', 'Cotización eliminada correctamente');

    }

    public function create($contactId)
    {
        
        $contactModel = new ContactsModel();
        $contact = $contactModel->find($contactId);

        if (!$contact) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        return view('crm/quotes/create', [
            'contact' => $contact
        ]);
    }

    public function store()
    {
        $db = \Config\Database::connect();
        $db->transBegin();

        try {

            // ================== 1️⃣ DATOS BASE ==================
            $data = $this->request->getPost();

            $contactModel = new ContactsModel();
            $companyModel = new CompaniesModel();

            $contactId   = $data['FK_Contact'];
            $companyName = trim($data['Company_name'] ?? '');

            // No guardar Company_name en t_quotes
            unset($data['Company_name']);

            // ================== EMPRESA ==================
            if ($companyName !== '') {

                $company = $companyModel
                    ->where('Company_name', $companyName)
                    ->first();

                if ($company) {
                    $companyId = $company['PK_Company'];
                } else {
                    $companyId = $companyModel->insert([
                        'Company_name' => $companyName,
                        'Created_at'   => date('Y-m-d H:i:s')
                    ]);

                    if (!$companyId) {
                        throw new \Exception('No se pudo crear la empresa');
                    }
                }

                // Actualizar contacto
                $contactModel->update($contactId, [
                    'PK_Company'   => $companyId,
                    'Company_name' => $companyName,
                    'Updated_at'   => date('Y-m-d H:i:s')
                ]);
            }

            // ================== DEFAULTS ==================
            unset($data['Quote_number']); // MUY IMPORTANTE

            $data['Status']     = 'Cotizacion';
            $data['Quoted_at']  = date('Y-m-d H:i:s');
            $data['Expires_at'] = date('Y-m-d H:i:s', strtotime('+15 days'));
            $data['Created_at'] = date('Y-m-d H:i:s');

            // ================== SERVICIOS ==================
            $services = $data['services'] ?? [];
            unset($data['services']);

            // ================== 2️⃣ INSERT QUOTE (SIN FOLIO) ==================
            $this->quoteModel->insert($data);
            $quoteId = $this->quoteModel->getInsertID();

            if (!$quoteId) {
                throw new \Exception('No se pudo crear la cotización');
            }

            // ================== 3️⃣ GENERAR FOLIO SEGURO ==================
            $year = date('Y');

            $quoteNumber = 'COT-' . $year . '-' . str_pad($quoteId, 6, '0', STR_PAD_LEFT);

            $this->quoteModel->update($quoteId, [
                'Quote_number' => $quoteNumber
            ]);

            // ================== 4️⃣ SERVICIOS ==================
            $servicesModel = new QuoteServicesModel();
            $operationCost = 0;
            $order = 1;

            if (is_array($services)) {
                foreach ($services as $service) {

                    if (empty($service['Service_name'])) continue;

                    $qty   = (float) ($service['Quantity'] ?? 1);
                    $price = (float) ($service['Unit_price'] ?? 0);
                    $total = $qty * $price;

                    $servicesModel->insert([
                        'FK_Quote'     => $quoteId,
                        'Service_type' => $service['Service_type'],
                        'Service_name' => $service['Service_name'],
                        'Description'  => $service['Description'] ?? null,
                        'Quantity'     => $qty,
                        'Unit_price'   => $price,
                        'Total'        => round($total, 2),
                        'Sort_order'   => $order++
                    ]);

                    $operationCost += $total;
                }
            }

            // ================== 5️⃣ CÁLCULO FINAL ==================
            $data['Operation_cost'] = $operationCost;

            $calculated = $this->calculateQuote($data);

            $this->quoteModel->update($quoteId, array_merge(
                $calculated,
                ['Updated_at' => date('Y-m-d H:i:s')]
            ));

            // ================== 6️⃣ COMMIT ==================
            $db->transCommit();

            return redirect()
                ->to('crm/quotes/view/' . $quoteId)
                ->with('swal', [
                    'icon'  => 'success',
                    'title' => 'Cotización creada',
                    'text'  => 'La cotización se guardó correctamente'
                ]);

        } catch (\Throwable $e) {

            $db->transRollback();

            log_message('error', 'Error en Quotes::store -> ' . $e->getMessage());

            return redirect()->back()
                ->withInput()
                ->with('swal', [
                    'icon'  => 'error',
                    'title' => 'Error',
                    'text'  => $e->getMessage()
                ]);
        }
    }


    public function update($id)
    {
        $model = new QuotesModel();

        $data = $this->request->getPost();

        // Recalcular SIEMPRE
        $calculated = $this->calculateQuote($data);

        $data = array_merge($data, $calculated);

        $model->update($id, $data);

        return redirect()
            ->to('/crm/quotes/view/' . $id)
            ->with('success', 'Cotización actualizada correctamente');
    }

    public function approve($quoteId)
    {
        $db = \Config\Database::connect();
        $db->transBegin();

        try {

            $statusRequested = $this->request->getPost('status');
            $amountPaid      = (float)$this->request->getPost('amount_paid');
            $method          = $this->request->getPost('payment_method');
            $currency        = $this->request->getPost('currency');
            $reference       = $this->request->getPost('reference');
            $notes           = $this->request->getPost('notes');
            $allowCredit     = $this->request->getPost('allow_credit') ? true : false;

            if (!in_array($statusRequested, ['Apartado', 'Orden de Envio'])) {
                throw new \Exception('Estado inválido');
            }

            $quote = $this->quoteModel->find($quoteId);
            if (!$quote) {
                throw new \Exception('Cotización no existe');
            }

            $total = (float)$quote['Total_amount'];

            // =========================
            // PAGOS
            // =========================
            $paymentModel = new \App\Models\Payments\QuotePaymentModel();

           // =========================
            // DETERMINAR TIPO PAGO
            // =========================

            $paymentType = null;

            if ($amountPaid >= $total) {
                $paymentType = 'Contado';
            }
            elseif ($amountPaid > 0 && !$allowCredit) {
                $paymentType = 'Parcial';
            }
            elseif ($amountPaid > 0 && $allowCredit) {
                $paymentType = 'Credito';
            }

            // =========================
            // INSERTAR PAGO
            // =========================

            if ($amountPaid > 0) {
                $paymentModel->insert([
                    'FK_Quote'       => $quoteId,
                    'Payment_method' => $method,
                    'Payment_type'   => $paymentType,
                    'Amount'         => $amountPaid,
                    'Reference'      => $reference,
                    'Notes'          => $notes,
                    'Paid_at'        => date('Y-m-d H:i:s'),
                    'Created_at'     => date('Y-m-d H:i:s'),
                    'Created_by'     => session('user_id') ?? null
                ]);
            }


            $paidSoFar = (float)$paymentModel
                ->selectSum('Amount')
                ->where('FK_Quote', $quoteId)
                ->get()
                ->getRow()
                ->Amount ?? 0;

            if ($paidSoFar > $total) $paidSoFar = $total;

            $balance = $total - $paidSoFar;

            // =========================
            // STATUS FINAL
            // =========================
            if ($paidSoFar >= $total) {
                $finalStatus = 'Orden de Envio';
            } elseif ($allowCredit) {
                $finalStatus = 'Orden de Envio';
            } else {
                $finalStatus = 'Apartado';
            }

            $data = $quote;
            unset($data['PK_Quote']);

            $data['FK_Quote']   = $quoteId;
            $data['Status']     = $finalStatus;
            $data['Created_at'] = date('Y-m-d H:i:s');

            $year = date('Y');

            $orderId = null;
            $apartadoId = null;

            // =========================
            // APARTADO
            // =========================
            if ($finalStatus === 'Apartado') {

                $apartadoModel = new \App\Models\Quotes\ApartadoModel();

                $row = $apartadoModel->where('FK_Quote', $quoteId)->first();

                if (!$row) {
                    $apartadoModel->insert($data);
                    $apartadoId = $apartadoModel->getInsertID();

                    $apartadoModel->update($apartadoId, [
                        'Apartado_number' =>
                            'APT-' . $year . '-' . str_pad($apartadoId, 6, '0', STR_PAD_LEFT)
                    ]);
                } else {
                    $apartadoId = $row['PK_Apartado'];
                }
            }

            // =========================
            // ORDEN ENVIO
            // =========================
            if ($finalStatus === 'Orden de Envio') {

                $orderModel = new \App\Models\Quotes\OrderModel();

                $row = $orderModel->where('FK_Quote', $quoteId)->first();

                if (!$row) {
                    $orderModel->insert($data);
                    $orderId = $orderModel->getInsertID();

                    $orderModel->update($orderId, [
                        'Order_number' =>
                            'ORD-' . $year . '-' . str_pad($orderId, 6, '0', STR_PAD_LEFT)
                    ]);
                } else {
                    $orderId = $row['PK_Order'];
                }
            }

            // =========================
            // UPDATE QUOTE
            // =========================
            $this->quoteModel->update($quoteId, [
                'Status'      => $finalStatus,
                'Paid_amount' => $paidSoFar,
                'Balance'     => $balance,
                'Updated_at'  => date('Y-m-d H:i:s')
            ]);

            // =========================
            // BALANCE
            // =========================
            $balanceModel = new \App\Models\Payments\QuoteBalanceModel();

            $balanceRow = $balanceModel->where('FK_Quote', $quoteId)->first();

            $balanceData = [
                'FK_Quote'     => $quoteId,
                'Total_amount' => $total,
                'Paid_amount'  => $paidSoFar,
                'Balance'      => $balance,
                'Payment_status' => $balance <= 0 ? 'Pagado' : 'Pendiente',
                'Updated_at'   => date('Y-m-d H:i:s')
            ];

            if ($balanceRow) {
                $balanceModel->update($balanceRow['PK_Balance'], $balanceData);
            } else {
                $balanceModel->insert($balanceData);
            }

            $db->transCommit();

            if ($finalStatus === 'Orden de Envio' && $orderId) {
                return redirect()
                    ->to('crm/orders/view/' . $orderId)
                    ->with('swal', [
                        'icon' => 'success',
                        'title' => 'Orden creada',
                        'text' => 'Redirigiendo a orden'
                    ]);
            }

            if ($finalStatus === 'Apartado' && $apartadoId) {
                return redirect()
                    ->to('crm/apartados/view/' . $apartadoId)
                    ->with('swal', [
                        'icon' => 'info',
                        'title' => 'Apartado creado',
                        'text' => 'Solo pagos habilitados'
                    ]);
            }

        } catch (\Throwable $e) {

            $db->transRollback();

            return redirect()->back()->with('swal', [
                'icon' => 'error',
                'title' => 'Error',
                'text' => $e->getMessage()
            ]);
        }
    }



    public function pdf($id)
    {   
        $lang = $this->request->getGet('lang') ?? 'es';
        $lang = in_array($lang, ['es', 'en']) ? $lang : 'es';

        $servicesModel = new QuoteServicesModel();

        $services = $servicesModel
            ->where('FK_Quote', $id)
            ->orderBy('Sort_order', 'ASC')
            ->findAll();

        $builder = $this->quoteModel
            ->select('
                t_quotes.*,

                -- Contacto(cliente)
                t_contacts.First_name,
                t_contacts.Last_name,
                t_contacts.Email,
                t_contacts.Phone,

                -- Empresa(companies)
                t_companies.Company_name,
                t_companies.Address AS Company_address,
                t_companies.City AS Company_city,
                t_companies.State AS Company_state,
                t_companies.Postal_code AS Company_zip,
                t_companies.Country AS Company_country,
                t_companies.Phone AS Company_phone,

                -- IDs según status(status)
                t_apartado.PK_Apartado,
                t_apartado.Apartado_number,
                t_orders.PK_Order,
                t_orders.Order_number
            ')
            ->join(
                't_contacts',
                't_contacts.PK_Contact = t_quotes.FK_Contact',
                'left'
            )
            ->join(
                't_companies',
                't_companies.PK_Company = t_contacts.PK_Company',
                'left'
            )
            ->join(
                't_apartado',
                't_apartado.FK_Quote = t_quotes.PK_Quote',
                'left'
            )
            ->join(
                't_orders',
                't_orders.FK_Quote = t_quotes.PK_Quote',
                'left'
            )
            ->where('t_quotes.PK_Quote', $id);

        $quote = $builder->first();

        if (!$quote) {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Cotización no encontrada');
        }

        $options = new Options();
        $options->set('isRemoteEnabled', true);
        $options->set('isHtml5ParserEnabled', true);
        $options->set('chroot', FCPATH);

        $dompdf = new Dompdf($options);

        $html = view('crm/quotes/pdf', [
            'quote'    => $quote,
            'services' => $services,
            'lang'     => $lang
        ]);

        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'portrait');
        $dompdf->render();

        return $this->response
            ->setHeader('Content-Type', 'application/pdf')
            ->setHeader(
                'Content-Disposition',
                'inline; filename="TEF-'.$quote['Quote_number'].'.pdf"'
            )
            ->setBody($dompdf->output());
    }


    public function view($id)
    {
        $quote = $this->quoteModel->find($id);

        if (!$quote) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $contactModel = new ContactsModel();
        $contact = $contactModel->find($quote['FK_Contact']);

        return view('crm/quotes/view', [
            'quote'   => $quote,
            'contact' => $contact
        ]);
    }

    public function listByContact($contactId)
    {
        $contactModel = new ContactsModel();
        $contact = $contactModel->find($contactId);

        if (!$contact) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $quotes = $this->quoteModel
            ->where('FK_Contact', $contactId)
            ->orderBy('Created_at', 'DESC')
            ->findAll();

        return view('crm/quotes/list', [
            'contact' => $contact,
            'quotes'  => $quotes
        ]);
    }


    private function calculateQuote(array $data): array
    {
        $operation = (float) ($data['Operation_cost'] ?? 0);

        $adminPct  = (float) ($data['Administrative_pct'] ?? 0);
        $packPct   = (float) ($data['Packaging_pct'] ?? 0);
        $marginPct = (float) ($data['Margin_pct'] ?? 0);
        $taxesPct  = (float) ($data['Taxes_pct'] ?? 0);

        // 1️⃣ Administrativo
        $adminCost = $operation * ($adminPct / 100);

        // 2️⃣ Base antes de embalaje
        $baseBeforePack = $operation + $adminCost;

        // 3️⃣ Embalaje
        $packagingCost = $baseBeforePack * ($packPct / 100);

        // 4️⃣ Base
        $baseCost = $baseBeforePack + $packagingCost;

        // 5️⃣ Margen
        $marginAmount = $baseCost * ($marginPct / 100);

        // 6️⃣ Subtotal
        $subtotal = $baseCost + $marginAmount;

        // 7️⃣ Impuestos
        $taxesAmount = $subtotal * ($taxesPct / 100);

        // 8️⃣ Total
        $total = $subtotal + $taxesAmount;

        return [
            'Operation_cost'        => round($operation, 2),
            'Administrative_cost'   => round($adminCost, 2),
            'Packaging_cost'        => round($packagingCost, 2),
            'Base_cost'             => round($baseCost, 2),
            'Margin_amount'         => round($marginAmount, 2),
            'Subtotal'              => round($subtotal, 2),
            'Taxes'                 => round($taxesAmount, 2),
            'Total_amount'          => round($total, 2),
        ];
    }

}
