<?php

namespace App\Services\Sales;

use App\Services\BaseService;
use App\Repositories\InvoiceRepository;
use App\Models\TaxInvoice;
use App\Models\TaxInvoiceItem;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Barryvdh\DomPDF\Facade\Pdf;

class InvoiceService extends BaseService
{
    protected InvoiceRepository $invoiceRepository;

    public function __construct(InvoiceRepository $repository)
    {
        parent::__construct($repository);
        $this->invoiceRepository = $repository;
    }

    /**
     * Get all invoices with relations
     */
    public function getAllWithRelations(): Collection
    {
        return $this->invoiceRepository->getAllWithRelations();
    }

    /**
     * Get invoices by company
     */
    public function getByCompany(int $companyId): Collection
    {
        return $this->invoiceRepository->getByCompany($companyId);
    }

    /**
     * Get invoices by status
     */
    public function getByStatus(string $status): Collection
    {
        return $this->invoiceRepository->getByStatus($status);
    }

    /**
     * Get pending invoices
     */
    public function getPending(): Collection
    {
        return $this->invoiceRepository->getPending();
    }

    /**
     * Get approved invoices
     */
    public function getApproved(): Collection
    {
        return $this->invoiceRepository->getApproved();
    }

    /**
     * Get invoices by date range
     */
    public function getByDateRange(string $startDate, string $endDate): Collection
    {
        return $this->invoiceRepository->getByDateRange($startDate, $endDate);
    }

    /**
     * Create invoice from sales order
     */
    public function createFromSalesOrder(int $salesOrderId, array $additionalData = []): TaxInvoice
    {
        return DB::transaction(function () use ($salesOrderId, $additionalData) {
            $salesOrder = \App\Models\SalesOrder::with(['items', 'customer'])->findOrFail($salesOrderId);

            $data = [
                'invoice_no' => $this->generateInvoiceNumber(),
                'invoice_date' => now()->toDateString(),
                'company_id' => $salesOrder->company_name,
                'address' => $salesOrder->company_address,
                'gst' => $salesOrder->company_gstn,
                'phone' => $salesOrder->company_phone,
                'email' => $salesOrder->company_email,
                'buyer_order_no' => $salesOrder->sales_order_no,
                'reference_date' => $salesOrder->sales_order_date,
                'taxable_value' => $salesOrder->subtotal,
                'sgst' => $salesOrder->sgst_amount,
                'cgst' => $salesOrder->cgst_amount,
                'igst' => $salesOrder->igst_amount,
                'total_tax_amount' => ($salesOrder->sgst_amount ?? 0) + ($salesOrder->cgst_amount ?? 0) + ($salesOrder->igst_amount ?? 0),
                'total_amount' => $salesOrder->grand_total,
                'amount_in_words' => $salesOrder->inr_in_words,
                'status' => 'Pending',
            ];

            // Merge additional data
            $data = array_merge($data, $additionalData);

            $invoice = $this->invoiceRepository->create($data);

            // Create invoice items from sales order items
            foreach ($salesOrder->items as $item) {
                TaxInvoiceItem::create([
                    'tax_invoice_id' => $invoice->id,
                    'description' => $item->description,
                    'hsn' => $item->hsn,
                    'quantity' => $item->quantity,
                    'unit' => $item->unit,
                    'rate' => $item->rate,
                    'amount' => $item->amount,
                ]);
            }

            $this->logAction('created Invoice from Sales Order', [
                'invoice_id' => $invoice->id,
                'invoice_no' => $invoice->invoice_no,
                'sales_order_id' => $salesOrderId,
            ]);

            return $invoice->load('items');
        });
    }

    /**
     * Create invoice with items
     */
    public function createWithItems(array $data, array $items = []): TaxInvoice
    {
        return DB::transaction(function () use ($data, $items) {
            // Generate invoice number if not provided
            if (empty($data['invoice_no'])) {
                $data['invoice_no'] = $this->generateInvoiceNumber();
            }

            // Calculate totals
            $data = $this->calculateTotals($data, $items);

            $invoice = $this->invoiceRepository->create($data);

            // Create items
            if (!empty($items)) {
                $this->createItems($invoice, $items);
            }

            $this->logAction('created Invoice', [
                'invoice_id' => $invoice->id,
                'invoice_no' => $invoice->invoice_no,
            ]);

            return $invoice->load('items');
        });
    }

    /**
     * Update invoice with items
     */
    public function updateWithItems(int $id, array $data, array $items = []): TaxInvoice
    {
        return DB::transaction(function () use ($id, $data, $items) {
            // Calculate totals
            $data = $this->calculateTotals($data, $items);

            $invoice = $this->invoiceRepository->update($id, $data);

            // Update items
            if (!empty($items)) {
                // Delete existing items
                $invoice->items()->delete();
                // Create new items
                $this->createItems($invoice, $items);
            }

            $this->logAction('updated Invoice', [
                'invoice_id' => $invoice->id,
                'invoice_no' => $invoice->invoice_no,
            ]);

            return $invoice->load('items');
        });
    }

    /**
     * Create items for invoice
     */
    protected function createItems(TaxInvoice $invoice, array $items): void
    {
        foreach ($items as $item) {
            TaxInvoiceItem::create([
                'tax_invoice_id' => $invoice->id,
                'description' => $item['description'] ?? '',
                'hsn' => $item['hsn'] ?? '',
                'quantity' => $item['quantity'] ?? 0,
                'unit' => $item['unit'] ?? '',
                'rate' => $item['rate'] ?? 0,
                'amount' => $item['amount'] ?? 0,
            ]);
        }
    }

    /**
     * Calculate totals
     */
    protected function calculateTotals(array $data, array $items): array
    {
        $taxableValue = 0;
        foreach ($items as $item) {
            $taxableValue += floatval($item['amount'] ?? 0);
        }

        $data['taxable_value'] = $taxableValue;

        // Calculate GST
        $sgst = floatval($data['sgst'] ?? 0);
        $cgst = floatval($data['cgst'] ?? 0);
        $igst = floatval($data['igst'] ?? 0);

        $data['total_tax_amount'] = $sgst + $cgst + $igst;
        $data['total_amount'] = $taxableValue + $data['total_tax_amount'];

        // Convert to words
        $data['amount_in_words'] = numberToWords($data['total_amount']);

        return $data;
    }

    /**
     * Generate next invoice number
     */
    public function generateInvoiceNumber(): string
    {
        $year = date('Y');
        $prefix = "INV/{$year}";
        return nextNumber($prefix, 'tax_invoices', 'invoice_no', 2);
    }

    /**
     * Approve invoice
     */
    public function approve(int $id, ?string $remarks = null): TaxInvoice
    {
        $invoice = $this->invoiceRepository->approve($id, auth()->id(), $remarks);

        $this->logAction('approved Invoice', [
            'invoice_id' => $invoice->id,
            'invoice_no' => $invoice->invoice_no,
        ]);

        return $invoice;
    }

    /**
     * Reject invoice
     */
    public function reject(int $id, ?string $remarks = null): TaxInvoice
    {
        $invoice = $this->invoiceRepository->reject($id, auth()->id(), $remarks);

        $this->logAction('rejected Invoice', [
            'invoice_id' => $invoice->id,
            'invoice_no' => $invoice->invoice_no,
        ]);

        return $invoice;
    }

    /**
     * Get for DataTable
     */
    public function getForDataTable()
    {
        return $this->invoiceRepository->getForDataTableWithRelations();
    }

    /**
     * Search invoices
     */
    public function search(string $term): Collection
    {
        return $this->invoiceRepository->search($term);
    }

    /**
     * Generate PDF
     */
    public function generatePdf(int $id, string $viewPath): \Illuminate\Http\Response
    {
        $invoice = $this->invoiceRepository->with(['items', 'company'])->find($id);

        $pdf = Pdf::loadView($viewPath, compact('invoice'));
        return $pdf->download("invoice-{$invoice->invoice_no}.pdf");
    }

    /**
     * Get revenue statistics
     */
    public function getRevenueStats(): array
    {
        $currentYear = date('Y');
        $currentMonth = date('m');

        return [
            'monthly_revenue' => $this->invoiceRepository->getRevenueByMonth($currentYear, $currentMonth),
            'yearly_revenue' => $this->invoiceRepository->getYearlyRevenue($currentYear),
            'pending_count' => $this->invoiceRepository->getByStatus('Pending')->count(),
            'approved_count' => $this->invoiceRepository->getByStatus('Approved')->count(),
        ];
    }
}
