<?php

namespace App\Http\Controllers\Base;

use App\Services\Sales\InvoiceService;
use App\Services\Sales\SalesOrderService;
use App\Models\CustomerVendor;
use App\Models\TaxInvoice;
use App\Models\SalesOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Yajra\DataTables\Facades\DataTables;

class BaseInvoiceController extends BaseController
{
    protected string $module = 'invoice';
    protected string $displayName = 'Invoice';
    protected array $listRelations = ['items', 'company'];
    protected array $showRelations = ['items', 'company'];

    protected InvoiceService $invoiceService;
    protected ?SalesOrderService $salesOrderService;

    public function __construct(InvoiceService $service, ?SalesOrderService $salesOrderService = null)
    {
        parent::__construct($service);
        $this->invoiceService = $service;
        $this->salesOrderService = $salesOrderService;
    }

    // ==========================================
    // LEGACY METHOD ALIASES (for backward compatibility with existing routes)
    // ==========================================

    /**
     * Legacy alias for create() - Show invoice creation form
     */
    public function invoicePage()
    {
        $companies = CustomerVendor::all();
        $sales_orders = $this->getAvailableSalesOrders();
        return $this->roleView('invoice.invoiceorder', compact('companies', 'sales_orders'));
    }

    /**
     * Legacy alias for index() - List all invoices
     */
    public function invoiceDetails()
    {
        $invoices = TaxInvoice::with('company')->get();
        return $this->roleView('invoice.invoicedetails', compact('invoices'));
    }

    /**
     * Generate invoice ID via AJAX
     */
    public function generateInvoiceIdAjax()
    {
        $invoiceNo = $this->generateInvoiceId();
        return response()->json(['invoice_no' => $invoiceNo]);
    }

    /**
     * Generate next invoice number
     */
    protected function generateInvoiceId(): string
    {
        $lastInvoice = TaxInvoice::orderBy('id', 'desc')->first();
        if ($lastInvoice && preg_match('/UEPL\/P\/INV\/(\d+)/', $lastInvoice->invoice_no, $matches)) {
            $lastNumber = (int)$matches[1];
            $newNumber = str_pad($lastNumber + 1, 4, '0', STR_PAD_LEFT);
        } else {
            $newNumber = '0001';
        }
        return "UEPL/P/INV/{$newNumber}";
    }

    /**
     * Get available sales orders (not yet invoiced)
     */
    protected function getAvailableSalesOrders($excludeInvoiceId = null)
    {
        $query = SalesOrder::with('items')
            ->where('status', 'approved')
            ->whereNotIn('sales_order_no', function ($q) use ($excludeInvoiceId) {
                $q->select('buyer_order_no')
                    ->from('tax_invoices')
                    ->whereNotNull('buyer_order_no');
                if ($excludeInvoiceId) {
                    $q->where('id', '!=', $excludeInvoiceId);
                }
            })
            ->orderBy('id');

        return $query->get();
    }

    // ==========================================
    // STANDARD CRUD METHODS
    // ==========================================

    /**
     * Display a listing of Invoices
     */
    public function index()
    {
        return $this->roleView('invoice.index');
    }

    /**
     * Get Invoices for DataTable
     */
    public function list()
    {
        $query = $this->invoiceService->getForDataTable();

        return DataTables::of($query)
            ->addIndexColumn()
            ->addColumn('company_name', function ($row) {
                return $row->company?->company_name ?? 'N/A';
            })
            ->editColumn('total_amount', function ($row) {
                return number_format($row->total_amount ?? 0, 2);
            })
            ->editColumn('status', function ($row) {
                $statusColors = [
                    'Pending' => 'warning',
                    'Approved' => 'success',
                    'Rejected' => 'danger',
                    'Paid' => 'info',
                ];
                $color = $statusColors[$row->status] ?? 'secondary';
                return '<span class="badge badge-' . $color . '">' . ($row->status ?? 'N/A') . '</span>';
            })
            ->addColumn('action', function ($row) {
                return $this->getInvoiceActionButtons($row);
            })
            ->rawColumns(['action', 'status'])
            ->make(true);
    }

    /**
     * Generate action buttons for Invoice
     */
    protected function getInvoiceActionButtons($row): string
    {
        $showRoute = route($this->resolveRoute('invoice.show'), $row->id);
        $editRoute = route($this->resolveRoute('invoice.edit'), $row->id);
        $printRoute = route($this->resolveRoute('invoice.print'), $row->id);

        $buttons = '
            <a href="' . $showRoute . '" class="btn btn-info btn-sm" title="View">
                <i class="fas fa-eye"></i>
            </a>
            <a href="' . $editRoute . '" class="btn btn-primary btn-sm" title="Edit">
                <i class="fas fa-edit"></i>
            </a>
            <a href="' . $printRoute . '" class="btn btn-secondary btn-sm" title="Print" target="_blank">
                <i class="fas fa-print"></i>
            </a>';

        // Add approve/reject buttons for pending invoices (SuperAdmin only handled in subclass)
        if ($row->status === 'Pending') {
            $buttons .= $this->getApprovalButtons($row);
        }

        $buttons .= '
            <button class="btn btn-danger btn-sm delete-btn" data-id="' . $row->id . '" title="Delete">
                <i class="fas fa-trash"></i>
            </button>
        ';

        return $buttons;
    }

    /**
     * Get approval buttons - override in subclass for role-specific behavior
     */
    protected function getApprovalButtons($row): string
    {
        return '';
    }

    /**
     * Show the form for creating a new Invoice
     */
    public function create()
    {
        $data = $this->getCreateData();
        $data['invoice_no'] = $this->invoiceService->generateInvoiceNumber();
        return $this->roleView('invoice.create', $data);
    }

    /**
     * Create invoice from sales order
     */
    public function createFromSalesOrder(int $salesOrderId)
    {
        $salesOrder = $this->salesOrderService->findByIdWith($salesOrderId, ['items', 'customer']);

        if (!$salesOrder) {
            return $this->redirectToRoute('sales.index')
                ->with('error', 'Sales Order not found.');
        }

        $data = $this->getCreateData();
        $data['salesOrder'] = $salesOrder;
        $data['invoice_no'] = $this->invoiceService->generateInvoiceNumber();

        return $this->roleView('invoice.createFromSalesOrder', $data);
    }

    /**
     * Get additional data for create/edit forms
     */
    protected function getCreateData(): array
    {
        return [
            'customers' => CustomerVendor::where('company_role', '!=', 'Vendor')->orderBy('company_name')->get(),
            'salesOrders' => $this->salesOrderService->getActive(),
            'statuses' => ['Pending', 'Approved', 'Rejected', 'Paid'],
        ];
    }

    /**
     * Store a newly created Invoice
     */
    public function store(Request $request)
    {
        Log::info($this->getLogPrefix() . ' Invoice store processing started');

        // Build items array from form arrays
        $items = $this->buildItemsArray($request);

        // Validate
        $this->validateStoreRequest($request);

        // Calculate tax totals
        $taxTotals = $this->calculateTaxTotals($request);

        DB::transaction(function () use ($request, $items, $taxTotals) {
            $invoice = TaxInvoice::create([
                'invoice_no' => $request->invoice_no,
                'invoice_date' => $request->invoice_date,
                'delivery_note' => $request->delivery_note,
                'terms_payment' => $request->terms_payment,
                'reference_no' => $request->reference_no,
                'other_reference' => $request->other_reference,
                'company_id' => $request->company,
                'address' => $request->address,
                'gst' => $request->gst,
                'phone' => $request->phone,
                'email' => $request->email,
                'buyer_order_no' => $request->buyer_order_no,
                'reference_date' => $request->reference_date ?: null,
                'dispatch_through' => $request->dispatch_through,
                'destination' => $request->destination,
                'vehicle_no' => $request->vehicle_no,
                'terms_of_delivery' => $request->terms_of_delivery,
                'taxable_value' => (float) ($request->taxable_value ?? 0),
                'sgst' => $taxTotals['sgst'],
                'cgst' => $taxTotals['cgst'],
                'igst' => $taxTotals['igst'],
                'total_tax_amount' => (float) ($request->total_tax_amount ?? 0),
                'total_amount' => (float) ($request->total_amount ?? 0),
                'amount_in_words' => $request->amount_in_words,
            ]);

            foreach ($items as $item) {
                $invoice->items()->create($item);
            }
        });

        return redirect()->route($this->resolveRoute('invoice.invoiceorder'))
            ->with('success', 'Invoice and items stored successfully.');
    }

    /**
     * Build items array from form arrays
     */
    protected function buildItemsArray(Request $request): array
    {
        $items = [];
        $count = count($request->description ?? []);

        for ($i = 0; $i < $count; $i++) {
            $items[] = [
                'description' => $request->description[$i],
                'hsn' => $request->hsn[$i],
                'quantity' => $request->quantity[$i],
                'rate' => $request->rate[$i],
                'per' => $request->per[$i],
                'sgst' => $request->sgst[$i] ?? 0,
                'cgst' => $request->cgst[$i] ?? 0,
                'igst' => $request->igst[$i] ?? 0,
                'amount' => $request->amount[$i],
            ];
        }

        return $items;
    }

    /**
     * Calculate tax totals from request
     */
    protected function calculateTaxTotals(Request $request): array
    {
        // Check for direct totals first
        $sgst_total = $request->sgst_total ?? 0;
        $cgst_total = $request->cgst_total ?? 0;
        $igst_total = $request->igst_total ?? 0;

        // If not provided, calculate from item arrays
        if (empty($sgst_total) && is_array($request->sgst)) {
            $sgst_total = collect($request->sgst)->map(fn($v) => floatval($v ?? 0))->sum();
        }
        if (empty($cgst_total) && is_array($request->cgst)) {
            $cgst_total = collect($request->cgst)->map(fn($v) => floatval($v ?? 0))->sum();
        }
        if (empty($igst_total) && is_array($request->igst)) {
            $igst_total = collect($request->igst)->map(fn($v) => floatval($v ?? 0))->sum();
        }

        return [
            'sgst' => (float) $sgst_total,
            'cgst' => (float) $cgst_total,
            'igst' => (float) $igst_total,
        ];
    }

    /**
     * Validate store request - can be overridden for role-specific validation
     */
    protected function validateStoreRequest(Request $request): void
    {
        $request->validate([
            'invoice_no' => 'required|unique:tax_invoices',
            'invoice_date' => 'required|date',
        ]);
    }

    /**
     * Display the specified Invoice
     */
    public function show(int $id)
    {
        $invoice = $this->invoiceService->findByIdWith($id, $this->showRelations);

        if (!$invoice) {
            return $this->redirectToRoute('invoice.index')
                ->with('error', 'Invoice not found.');
        }

        return $this->roleView('invoice.show', compact('invoice'));
    }

    /**
     * Show the form for editing the specified Invoice
     */
    public function edit($id)
    {
        $invoice = TaxInvoice::with(['company', 'items'])->findOrFail($id);
        $companies = CustomerVendor::all();
        $sales_orders = $this->getAvailableSalesOrdersForEdit($invoice);

        return $this->roleView('invoice.edit', compact('invoice', 'companies', 'sales_orders'));
    }

    /**
     * Get available sales orders for edit (includes currently linked one)
     */
    protected function getAvailableSalesOrdersForEdit($invoice)
    {
        return SalesOrder::where('status', 'approved')
            ->where(function($query) use ($invoice) {
                $query->whereNotIn('sales_order_no', function ($q) use ($invoice) {
                    $q->select('buyer_order_no')
                        ->from('tax_invoices')
                        ->whereNotNull('buyer_order_no')
                        ->where('id', '!=', $invoice->id);
                })
                ->orWhere('sales_order_no', $invoice->buyer_order_no);
            })
            ->orderBy('id')
            ->get();
    }

    /**
     * Update the specified Invoice
     */
    public function update(Request $request, $id)
    {
        Log::info($this->getLogPrefix() . ' Invoice update processing started', ['id' => $id]);

        $invoice = TaxInvoice::findOrFail($id);

        // Build items array from form arrays
        $items = $this->buildItemsArray($request);

        // Validate update request
        $this->validateUpdateRequest($request);

        // Calculate tax totals
        $taxTotals = $this->calculateTaxTotals($request);

        DB::transaction(function () use ($request, $items, $invoice, $taxTotals) {
            $invoice->update([
                'invoice_date' => $request->invoice_date,
                'delivery_note' => $request->delivery_note,
                'terms_payment' => $request->terms_payment,
                'reference_no' => $request->reference_no,
                'other_reference' => $request->other_reference,
                'company_id' => $request->company,
                'address' => $request->address,
                'gst' => $request->gst,
                'phone' => $request->phone,
                'email' => $request->email,
                'buyer_order_no' => $request->buyer_order_no,
                'reference_date' => $request->reference_date,
                'dispatch_through' => $request->dispatch_through,
                'destination' => $request->destination,
                'vehicle_no' => $request->vehicle_no,
                'terms_of_delivery' => $request->terms_of_delivery,
                'taxable_value' => $request->taxable_value,
                'sgst' => $taxTotals['sgst'],
                'cgst' => $taxTotals['cgst'],
                'igst' => $taxTotals['igst'],
                'total_tax_amount' => $request->total_tax_amount,
                'total_amount' => $request->total_amount,
                'amount_in_words' => $request->amount_in_words,
            ]);

            // Delete existing items and re-create
            $invoice->items()->delete();
            foreach ($items as $item) {
                $invoice->items()->create($item);
            }
        });

        return redirect()->route($this->resolveRoute('invoice.invoicedetails'))
            ->with('success', 'Invoice updated successfully.');
    }

    /**
     * Validate update request - can be overridden for role-specific validation
     */
    protected function validateUpdateRequest(Request $request): void
    {
        $request->validate([
            'invoice_date' => 'required|date',
        ]);
    }

    /**
     * Remove the specified Invoice
     */
    public function destroy(int $id): \Illuminate\Http\JsonResponse
    {
        try {
            $invoice = TaxInvoice::findOrFail($id);

            DB::transaction(function () use ($invoice) {
                // Delete related items first
                $invoice->items()->delete();
                // Delete the invoice
                $invoice->delete();
            });

            return response()->json(['success' => true, 'message' => 'Invoice deleted successfully.']);
        } catch (\Exception $e) {
            Log::error('Invoice deletion failed: ' . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Failed to delete invoice.'], 500);
        }
    }

    /**
     * Print Invoice
     */
    public function print($id)
    {
        $invoice = TaxInvoice::with(['company', 'items'])->findOrFail($id);
        return $this->roleView('invoice.print', compact('invoice'));
    }

    /**
     * Approve an invoice
     */
    public function approve($id)
    {
        try {
            $invoice = TaxInvoice::findOrFail($id);

            if ($invoice->status !== 'pending') {
                return response()->json(['success' => false, 'message' => 'Invoice is already ' . $invoice->status], 422);
            }

            $invoice->update([
                'status' => 'approved',
                'approved_by' => auth()->id(),
                'approved_at' => now(),
                'approval_remarks' => request('remarks')
            ]);

            return response()->json(['success' => true, 'message' => 'Invoice approved successfully.']);
        } catch (\Exception $e) {
            Log::error('Invoice approval failed: ' . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Failed to approve invoice.'], 500);
        }
    }

    /**
     * Reject an invoice
     */
    public function reject($id)
    {
        try {
            $invoice = TaxInvoice::findOrFail($id);

            if ($invoice->status !== 'pending') {
                return response()->json(['success' => false, 'message' => 'Invoice is already ' . $invoice->status], 422);
            }

            $invoice->update([
                'status' => 'rejected',
                'approved_by' => auth()->id(),
                'approved_at' => now(),
                'approval_remarks' => request('remarks')
            ]);

            return response()->json(['success' => true, 'message' => 'Invoice rejected successfully.']);
        } catch (\Exception $e) {
            Log::error('Invoice rejection failed: ' . $e->getMessage());
            return response()->json(['success' => false, 'message' => 'Failed to reject invoice.'], 500);
        }
    }

    /**
     * Get validation rules
     */
    protected function getValidationRules(): array
    {
        return [
            'invoice_no' => 'nullable|string|max:50',
            'invoice_date' => 'required|date',
            'delivery_note' => 'nullable|string|max:255',
            'terms_payment' => 'nullable|string|max:255',
            'reference_no' => 'nullable|string|max:100',
            'other_reference' => 'nullable|string|max:255',
            'company_id' => 'required|exists:customer_vendors,id',
            'address' => 'nullable|string',
            'gst' => 'nullable|string|max:50',
            'phone' => 'nullable|string|max:20',
            'email' => 'nullable|email|max:100',
            'buyer_order_no' => 'nullable|string|max:100',
            'reference_date' => 'nullable|date',
            'dispatch_through' => 'nullable|string|max:255',
            'destination' => 'nullable|string|max:255',
            'vehicle_no' => 'nullable|string|max:50',
            'terms_of_delivery' => 'nullable|string|max:255',
            'taxable_value' => 'nullable|numeric|min:0',
            'sgst' => 'nullable|numeric|min:0',
            'cgst' => 'nullable|numeric|min:0',
            'igst' => 'nullable|numeric|min:0',
            'total_tax_amount' => 'nullable|numeric|min:0',
            'total_amount' => 'nullable|numeric|min:0',
            'status' => 'nullable|in:Pending,Approved,Rejected,Paid',
        ];
    }

    /**
     * Search Invoices (AJAX)
     */
    public function search(Request $request)
    {
        $term = $request->input('q', '');
        $invoices = $this->invoiceService->search($term);

        return response()->json([
            'results' => $invoices->map(function ($invoice) {
                return [
                    'id' => $invoice->id,
                    'text' => $invoice->invoice_no . ' - ' . ($invoice->company?->company_name ?? 'N/A'),
                ];
            }),
        ]);
    }

    /**
     * Get revenue statistics
     */
    public function revenueStats()
    {
        $stats = $this->invoiceService->getRevenueStats();

        return response()->json($stats);
    }
}
