<?php

namespace App\Controllers;

use App\Models\InvoiceModel;
use App\Models\InvoiceLineModel;
use App\Models\ClientModel;
use App\Models\CompanyModel;
use App\Models\PaymentModel;
use App\Services\InvoiceCalculatorService;
use App\Services\PdfGeneratorService;
use App\Services\NumberToWordsService;
use App\Services\ExcelImportService;
use CodeIgniter\Controller;

class InvoiceController extends Controller
{
    protected $helpers = ['url', 'form', 'number'];
    protected InvoiceCalculatorService $calculator;
    protected PdfGeneratorService $pdfService;
    protected NumberToWordsService $wordsService;

    public function __construct()
    {
        $this->calculator = new InvoiceCalculatorService();
        $this->pdfService = new PdfGeneratorService();
        $this->wordsService = new NumberToWordsService();
    }

    public function index()
    {
        $companyId = session()->get('company_id') ?? 1;
        $invoiceModel = new InvoiceModel();

        $perPage = 20;
        $page = $this->request->getGet('page') ?? 1;
        $search = $this->request->getGet('search');
        $status = $this->request->getGet('status');

        $builder = $invoiceModel->where('company_id', $companyId);

        if ($search) {
            $builder->groupStart()
                ->like('invoice_number', $search)
                ->orLike('designation_global', $search)
                ->orLike('reference_client', $search)
                ->groupEnd();
        }

        if ($status) {
            $builder->where('status', $status);
        }

        $invoices = $builder->orderBy('date', 'DESC')
            ->paginate($perPage, 'default', $page);

        $pager = $invoiceModel->pager;

        return view('invoices/index', [
            'invoices' => $invoices,
            'pager' => $pager,
            'search' => $search,
            'status' => $status,
        ]);
    }

    public function create()
    {
        $companyId = session()->get('company_id') ?? 1;
        $clientModel = new ClientModel();
        $companyModel = new CompanyModel();

        $clients = $clientModel->where('company_id', $companyId)->where('is_active', 1)->findAll();
        $company = $companyModel->find($companyId);

        if ($this->request->getMethod() === 'post') {
            return $this->store();
        }

        return view('invoices/form', [
            'invoice' => null,
            'lines' => [],
            'clients' => $clients,
            'company' => $company,
            'mode' => 'create',
        ]);
    }

    public function store()
    {
        $companyId = session()->get('company_id') ?? 1;
        $userId = session()->get('user_id');

        $invoiceData = $this->request->getPost('invoice');
        $linesData = $this->request->getPost('lines') ?? [];

        $linesData = $this->calculator->recalculateLines($linesData);

        $vatRate = (float) ($invoiceData['vat_rate'] ?? 0.19);
        $discountPercent = (float) ($invoiceData['discount_percent'] ?? 0);
        $advance = (float) ($invoiceData['advance_amount'] ?? 0);
        $stampDuty = (float) ($invoiceData['stamp_duty'] ?? 1);

        $totals = $this->calculator->calculate($linesData, $vatRate, $discountPercent, $advance, $stampDuty);

        $invoiceModel = new InvoiceModel();
        $companyModel = new CompanyModel();
        $company = $companyModel->find($companyId);
        $invoiceNumber = $invoiceModel->generateNumber($companyId, $company['invoice_prefix'], date('Y'));

        $invoice = [
            'company_id' => $companyId,
            'client_id' => $invoiceData['client_id'],
            'user_id' => $userId,
            'invoice_number' => $invoiceNumber,
            'invoice_type' => $invoiceData['invoice_type'] ?? 'facture',
            'status' => 'brouillon',
            'date' => $invoiceData['date'] ?? date('Y-m-d'),
            'due_date' => $invoiceData['due_date'] ?? date('Y-m-d', strtotime('+30 days')),
            'reference_client' => $invoiceData['reference_client'] ?? null,
            'customs_code' => $invoiceData['customs_code'] ?? null,
            'reper_number' => $invoiceData['reper_number'] ?? null,
            'designation_global' => $invoiceData['designation_global'] ?? null,
            'gross_weight' => $invoiceData['gross_weight'] ?? null,
            'weight_unit' => $invoiceData['weight_unit'] ?? 'KGS',
            'package_count' => $invoiceData['package_count'] ?? null,
            'currency_value' => $invoiceData['currency_value'] ?? null,
            'currency_unit' => $invoiceData['currency_unit'] ?? 'EUR',
            'shipper' => $invoiceData['shipper'] ?? null,
            'declaration_number' => $invoiceData['declaration_number'] ?? null,
            'regime' => $invoiceData['regime'] ?? null,
            'quittance_number' => $invoiceData['quittance_number'] ?? null,
            'quittance_amount' => $invoiceData['quittance_amount'] ?? null,
            'subtotal' => $totals['subtotal'],
            'discount_amount' => $totals['discount_amount'],
            'discount_percent' => $totals['discount_percent'],
            'vat_base' => $totals['vat_base'],
            'vat_amount' => $totals['vat_amount'],
            'vat_rate' => $totals['vat_rate'],
            'stamp_duty' => $totals['stamp_duty'],
            'total_ht' => $totals['total_ht'],
            'total_ttc' => $totals['total_ttc'],
            'advance_amount' => $totals['advance_amount'],
            'net_payable' => $totals['net_payable'],
            'amount_in_words' => $this->wordsService->toWords($totals['net_payable']),
            'notes' => $invoiceData['notes'] ?? null,
            'terms' => $invoiceData['terms'] ?? null,
        ];

        $invoiceId = $invoiceModel->insert($invoice);

        $lineModel = new InvoiceLineModel();
        foreach ($linesData as $index => $line) {
            $line['invoice_id'] = $invoiceId;
            $line['sort_order'] = $index;
            $lineModel->insert($line);
        }

        session()->setFlashdata('success', 'Facture creee avec succes: ' . $invoiceNumber);
        return redirect()->to('/invoices/view/' . $invoiceId);
    }

    public function view(int $id)
    {
        $invoiceModel = new InvoiceModel();
        $invoice = $invoiceModel->getWithDetails($id);

        if (!$invoice) {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Facture non trouvee');
        }

        return view('invoices/view', ['invoice' => $invoice]);
    }

    public function edit(int $id)
    {
        $invoiceModel = new InvoiceModel();
        $invoice = $invoiceModel->getWithDetails($id);

        if (!$invoice || $invoice['status'] !== 'brouillon') {
            session()->setFlashdata('error', 'Seules les factures en brouillon peuvent etre modifiees');
            return redirect()->to('/invoices');
        }

        $companyId = session()->get('company_id') ?? 1;
        $clientModel = new ClientModel();
        $companyModel = new CompanyModel();

        $clients = $clientModel->where('company_id', $companyId)->where('is_active', 1)->findAll();
        $company = $companyModel->find($companyId);

        return view('invoices/form', [
            'invoice' => $invoice,
            'lines' => $invoice['lines'],
            'clients' => $clients,
            'company' => $company,
            'mode' => 'edit',
        ]);
    }

    public function delete(int $id)
    {
        $invoiceModel = new InvoiceModel();
        $invoice = $invoiceModel->find($id);

        if (!$invoice) {
            return $this->response->setJSON(['success' => false, 'message' => 'Facture non trouvee']);
        }

        $invoiceModel->delete($id);

        return $this->response->setJSON(['success' => true, 'message' => 'Facture supprimee']);
    }

    public function pdf(int $id)
    {
        $invoiceModel = new InvoiceModel();
        $invoice = $invoiceModel->getWithDetails($id);

        if (!$invoice) {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Facture non trouvee');
        }

        $companyModel = new CompanyModel();
        $company = $companyModel->find($invoice['company_id']);

        $filepath = $this->pdfService->generateInvoice($company, $invoice, $invoice['lines'], $invoice['client']);

        $invoiceModel->update($id, ['pdf_path' => $filepath]);

        return $this->response->download($filepath, null)->setFileName('FACTURE_' . str_replace('/', '_', $invoice['invoice_number']) . '.pdf');
    }

    public function ajaxCalculate()
    {
        $lines = $this->request->getPost('lines') ?? [];
        $vatRate = (float) ($this->request->getPost('vat_rate') ?? 0.19);
        $discount = (float) ($this->request->getPost('discount_percent') ?? 0);
        $advance = (float) ($this->request->getPost('advance_amount') ?? 0);
        $stampDuty = (float) ($this->request->getPost('stamp_duty') ?? 1);

        $lines = $this->calculator->recalculateLines($lines);
        $totals = $this->calculator->calculate($lines, $vatRate, $discount, $advance, $stampDuty);
        $totals['amount_in_words'] = $this->wordsService->toWords($totals['net_payable']);

        return $this->response->setJSON([
            'success' => true,
            'lines' => $lines,
            'totals' => $totals,
        ]);
    }

    public function importExcel()
    {
        if ($this->request->getMethod() !== 'post') {
            return view('invoices/import');
        }

        $file = $this->request->getFile('excel_file');
        if (!$file || !$file->isValid()) {
            session()->setFlashdata('error', 'Fichier invalide');
            return redirect()->back();
        }

        $importService = new ExcelImportService();
        $result = $importService->importInvoice($file->getTempName());

        session()->setFlashdata('import_data', $result);
        return redirect()->to('/invoices/create');
    }

    public function markPaid(int $id)
    {
        $invoiceModel = new InvoiceModel();
        $paymentModel = new PaymentModel();

        $invoice = $invoiceModel->find($id);
        if (!$invoice) {
            return $this->response->setJSON(['success' => false]);
        }

        $amount = (float) $this->request->getPost('amount');
        $method = $this->request->getPost('method') ?? 'virement';

        $paymentModel->insert([
            'invoice_id' => $id,
            'amount' => $amount,
            'payment_date' => date('Y-m-d'),
            'payment_method' => $method,
            'reference' => $this->request->getPost('reference'),
            'created_by' => session()->get('user_id'),
        ]);

        $totalPaid = $paymentModel->getTotalPaid($id);
        $newStatus = ($totalPaid >= $invoice['net_payable']) ? 'payee' : 'partielle';

        $invoiceModel->update($id, [
            'status' => $newStatus,
            'paid_at' => ($newStatus === 'payee') ? date('Y-m-d H:i:s') : null,
        ]);

        return $this->response->setJSON(['success' => true, 'status' => $newStatus]);
    }
}
