<?php

namespace App\Http\Controllers\Modules\Sales;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\TaxInvoice;
use App\Models\TaxInvoiceItem;
use App\Models\CustomerVendor;
use App\Models\SalesOrder;
use App\Services\Sales\InvoiceService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Yajra\DataTables\Facades\DataTables;

/**
 * Unified Invoice Controller
 *
 * Handles tax invoice management for all roles.
 * Reference: SuperAdminInvoiceController, BaseInvoiceController
 */
class InvoiceController extends Controller
{
    use HasRoleViews;

    protected InvoiceService $invoiceService;

    public function __construct(InvoiceService $invoiceService)
    {
        $this->invoiceService = $invoiceService;
    }

    /**
     * Display the invoice creation form
     * Alias: invoicePage() for backward compatibility
     */
    public function invoicePage()
    {
        return $this->create();
    }

    /**
     * Display the invoice creation form
     */
    public function create()
    {
        $companies = CustomerVendor::select('id', 'company')->get();
        $sales_orders = $this->getAvailableSalesOrders();

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

    /**
     * Display the invoice list page
     * Alias: invoiceDetails() for backward compatibility
     */
    public function invoiceDetails()
    {
        return $this->index();
    }

    /**
     * Display the invoice list page
     */
    public function index()
    {
        $invoices = TaxInvoice::with('company')->orderBy('id', 'desc')->get();

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

    /**
     * Get invoices for DataTable (AJAX)
     */
    public function list()
    {
        $query = TaxInvoice::with('company')->orderBy('id', 'desc');

        return DataTables::of($query)
            ->addIndexColumn()
            ->addColumn('company_name', function ($row) {
                return $row->company?->company ?? '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[strtolower($row->status ?? '')] ?? 'secondary';
                return '<span class="badge badge-' . $color . '">' . ucfirst($row->status ?? 'N/A') . '</span>';
            })
            ->addColumn('action', function ($row) {
                return $this->getActionButtons($row);
            })
            ->rawColumns(['action', 'status'])
            ->make(true);
    }

    /**
     * Generate action buttons
     */
    protected function getActionButtons($row): string
    {
        $buttons = '
            <a href="' . route($this->resolveRoute('invoice.show'), $row->id) . '" class="btn btn-info btn-sm" title="View">
                <i class="fas fa-eye"></i>
            </a>
            <a href="' . route($this->resolveRoute('invoice.edit'), $row->id) . '" class="btn btn-primary btn-sm" title="Edit">
                <i class="fas fa-edit"></i>
            </a>
            <a href="' . route($this->resolveRoute('invoice.print'), $row->id) . '" class="btn btn-secondary btn-sm" title="Print" target="_blank">
                <i class="fas fa-print"></i>
            </a>';

        if ($this->isSuperAdmin() && strtolower($row->status ?? '') === 'pending') {
            $buttons .= '
                <button class="btn btn-success btn-sm approve-btn" data-id="' . $row->id . '" title="Approve">
                    <i class="fas fa-check"></i>
                </button>
                <button class="btn btn-warning btn-sm reject-btn" data-id="' . $row->id . '" title="Reject">
                    <i class="fas fa-times"></i>
                </button>';
        }

        $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;
    }

    /**
     * Generate Invoice ID (AJAX)
     * Alias: generateInvoiceIdAjax() for backward compatibility
     */
    public function generateInvoiceIdAjax(): JsonResponse
    {
        return $this->generateInvoiceId();
    }

    /**
     * Generate Invoice ID (AJAX)
     */
    public function generateInvoiceId(): JsonResponse
    {
        try {
            $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';
            }
            $invoiceNo = "UEPL/P/INV/{$newNumber}";

            return response()->json(['invoice_no' => $invoiceNo]);
        } catch (\Exception $e) {
            return response()->json(['invoice_no' => 'UEPL/P/INV/0001']);
        }
    }

    /**
     * Get available sales orders for invoice
     */
    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();
    }

    /**
     * Get sales order details (AJAX)
     */
    public function getSalesOrderDetails(int $id): JsonResponse
    {
        $salesOrder = SalesOrder::with(['items', 'customer'])->find($id);

        if (!$salesOrder) {
            return response()->json(['error' => 'Sales Order not found'], 404);
        }

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

    /**
     * Store a newly created invoice
     */
    public function store(Request $request)
    {
        Log::info('[Invoice] Store called');

        $validated = $request->validate([
            'invoice_no' => 'required|unique:tax_invoices,invoice_no',
            'invoice_date' => 'required|date',
            'company' => 'required|exists:customer_vendors,id',
        ]);

        try {
            DB::beginTransaction();

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

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

            // Resolve buyer_order_no: if a sales order was selected (order_no),
            // look up its sales_order_no; otherwise fall back to buyer_order_no field.
            $buyerOrderNo = $request->buyer_order_no;
            if (empty($buyerOrderNo) && $request->order_no) {
                $salesOrder = SalesOrder::find($request->order_no);
                $buyerOrderNo = $salesOrder?->sales_order_no;
            }

            $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' => $buyerOrderNo,
                '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,
                'status' => 'pending',
            ]);

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

            DB::commit();

            return $this->redirectToRoute('invoice.invoicedetails')
                ->with('success', 'Invoice created successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('[Invoice] Store Error: ' . $e->getMessage());
            return back()->with('error', 'Failed to create invoice: ' . $e->getMessage());
        }
    }

    /**
     * Build items array from form
     */
    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] ?? 0,
                'rate' => $request->rate[$i] ?? 0,
                'per' => $request->per[$i] ?? '',
                'sgst' => $request->sgst[$i] ?? 0,
                'cgst' => $request->cgst[$i] ?? 0,
                'igst' => $request->igst[$i] ?? 0,
                'amount' => $request->amount[$i] ?? 0,
            ];
        }

        return $items;
    }

    /**
     * Calculate tax totals
     */
    protected function calculateTaxTotals(Request $request): array
    {
        // The summary fields (sgst_total, cgst_total, igst_total) hold the computed
        // tax amounts from JavaScript. Use them if present; otherwise compute from
        // the per-item quantity, rate, and tax percentage arrays.
        $sgst_total = $request->sgst_total;
        $cgst_total = $request->cgst_total;
        $igst_total = $request->igst_total;

        // Only fall back to manual calculation when the summary field is truly absent
        // (not just zero). PHP's empty() treats "0" and "0.00" as empty, so use is_null.
        if (is_null($sgst_total) && is_array($request->input('sgst'))) {
            $sgst_total = $this->computeTaxFromItems($request, 'sgst');
        }
        if (is_null($cgst_total) && is_array($request->input('cgst'))) {
            $cgst_total = $this->computeTaxFromItems($request, 'cgst');
        }
        if (is_null($igst_total) && is_array($request->input('igst'))) {
            $igst_total = $this->computeTaxFromItems($request, 'igst');
        }

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

    /**
     * Compute tax amount from per-item arrays (quantity * rate * taxPercent / 100)
     */
    protected function computeTaxFromItems(Request $request, string $taxField): float
    {
        $total = 0.0;
        $quantities = $request->input('quantity', []);
        $rates = $request->input('rate', []);
        $percentages = $request->input($taxField, []);

        $count = count($percentages);
        for ($i = 0; $i < $count; $i++) {
            $qty = floatval($quantities[$i] ?? 0);
            $rate = floatval($rates[$i] ?? 0);
            $pct = floatval($percentages[$i] ?? 0);
            $total += ($qty * $rate * $pct / 100);
        }

        return $total;
    }

    /**
     * Display the specified invoice
     */
    public function show(int $id)
    {
        $invoice = TaxInvoice::with(['company', 'items'])->findOrFail($id);
        return $this->roleView('invoice.show', compact('invoice'));
    }

    /**
     * Display the edit form
     */
    public function edit(int $id)
    {
        $invoice = TaxInvoice::with(['company', 'items'])->findOrFail($id);
        $companies = CustomerVendor::select('id', 'company')->get();
        $sales_orders = $this->getAvailableSalesOrders($id);

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

    /**
     * Update the specified invoice
     */
    public function update(Request $request, int $id)
    {
        Log::info('[Invoice] Update called', ['id' => $id]);

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

        $validated = $request->validate([
            'invoice_date' => 'required|date',
        ]);

        try {
            DB::beginTransaction();

            $items = $this->buildItemsArray($request);
            $taxTotals = $this->calculateTaxTotals($request);

            $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,
            ]);

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

            DB::commit();

            return $this->redirectToRoute('invoice.invoicedetails')
                ->with('success', 'Invoice updated successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('[Invoice] Update Error: ' . $e->getMessage());
            return back()->with('error', 'Failed to update invoice: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified invoice
     */
    public function destroy(int $id): JsonResponse
    {
        // Authorization check - only SuperAdmin and Manager can delete
        if (!$this->isSuperAdmin() && !$this->isManager()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized. Only SuperAdmin or Manager can delete invoices.',
            ], 403);
        }

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

            // Prevent deletion of approved invoices (except by SuperAdmin)
            if ($invoice->status === 'approved' && !$this->isSuperAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot delete approved invoices. Contact SuperAdmin.',
                ], 403);
            }

            // Prevent deletion if invoice has payments
            $hasPayments = \App\Models\SalesPayment::where('invoice_id', $invoice->id)->exists();
            if ($hasPayments && !$this->isSuperAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot delete invoices with payments. Contact SuperAdmin.',
                ], 403);
            }

            DB::transaction(function () use ($invoice) {
                $invoice->items()->delete();
                $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);
        }
    }

    /**
     * Approve an invoice (SuperAdmin only)
     */
    public function approve(int $id): JsonResponse
    {
        if (!$this->isSuperAdmin()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        try {
            $invoice = TaxInvoice::findOrFail($id);
            $invoice->status = 'approved';
            $invoice->approved_by = auth()->id();
            $invoice->approved_at = now();
            $invoice->save();

            return response()->json(['success' => true, 'message' => 'Invoice approved!']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Failed to approve.'], 500);
        }
    }

    /**
     * Reject an invoice (SuperAdmin only)
     */
    public function reject(int $id): JsonResponse
    {
        if (!$this->isSuperAdmin()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        try {
            $invoice = TaxInvoice::findOrFail($id);
            $invoice->status = 'rejected';
            $invoice->approved_by = auth()->id();
            $invoice->approved_at = now();
            $invoice->save();

            return response()->json(['success' => true, 'message' => 'Invoice rejected!']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Failed to reject.'], 500);
        }
    }

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