<?php

namespace App\Http\Controllers;

use App\Models\AccountHead;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Project;
use App\Services\AccountingService;
use App\Services\CodeGeneratorService;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class InvoiceController extends Controller
{
    public function __construct(
        private CodeGeneratorService $codeGenerator,
        private AccountingService $accounting
    ) {}

    public function dashboard(): Response
    {
        $this->authorize('viewAny', Invoice::class);

        $stats = [
            'total_receivable' => Invoice::whereNotIn('status', ['paid', 'cancelled'])->selectRaw('SUM(grand_total - paid_amount) as total')->value('total') ?? 0,
            'total_payable' => \App\Models\VendorPayment::selectRaw('0')->value('0') ?? 0, // computed separately
            'cash_balance' => \App\Models\JournalLine::whereHas('accountHead', fn($q) => $q->where('code', '1001'))
                ->selectRaw('SUM(CASE WHEN type="debit" THEN amount ELSE -amount END) as balance')->value('balance') ?? 0,
            'bank_balance' => \App\Models\JournalLine::whereHas('accountHead', fn($q) => $q->where('code', '1002'))
                ->selectRaw('SUM(CASE WHEN type="debit" THEN amount ELSE -amount END) as balance')->value('balance') ?? 0,
        ];

        $recentTransactions = collect();

        $overdueInvoices = Invoice::with('client')
            ->whereNotIn('status', ['paid', 'cancelled'])
            ->where('due_date', '<', today())
            ->orderBy('due_date')
            ->limit(10)
            ->get();

        return Inertia::render('Accounts/Dashboard', [
            'stats' => $stats,
            'overdueInvoices' => $overdueInvoices,
        ]);
    }

    public function index(Request $request): Response
    {
        $this->authorize('viewAny', Invoice::class);

        $invoices = Invoice::with(['client', 'project'])
            ->when($request->status, fn($q, $s) => $q->where('status', $s))
            ->when($request->client_id, fn($q, $c) => $q->where('client_id', $c))
            ->orderByDesc('invoice_date')
            ->paginate(25)->withQueryString();

        return Inertia::render('Accounts/Invoices/Index', [
            'invoices' => $invoices,
            'filters' => $request->only(['status', 'client_id', 'project_id']),
        ]);
    }

    public function create(): Response
    {
        $this->authorize('create', Invoice::class);

        return Inertia::render('Accounts/Invoices/Create', [
            'clients' => Client::where('is_active', true)->select('id', 'name', 'code')->get(),
            'projects' => Project::whereNotIn('status', ['completed', 'cancelled'])->select('id', 'name', 'code')->get(),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $this->authorize('create', Invoice::class);

        $validated = $request->validate([
            'client_id' => 'required|uuid|exists:clients,id',
            'project_id' => 'nullable|uuid|exists:projects,id',
            'invoice_date' => 'required|date',
            'due_date' => 'required|date|after_or_equal:invoice_date',
            'vat_pct' => 'nullable|numeric|min:0|max:100',
            'discount_amount' => 'nullable|numeric|min:0',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'status' => 'required|in:draft,sent',
            'items' => 'required|array|min:1',
            'items.*.description' => 'required|string|max:250',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_rate' => 'required|numeric|min:0',
            'items.*.sequence' => 'nullable|integer',
        ]);

        $invoice = DB::transaction(function () use ($validated) {
            $code = $this->codeGenerator->generate('INV', 'invoices');

            $subtotal = collect($validated['items'])->sum(fn($i) => $i['quantity'] * $i['unit_rate']);
            $vatPct = $validated['vat_pct'] ?? 0;
            $vatAmount = $subtotal * ($vatPct / 100);
            $discount = $validated['discount_amount'] ?? 0;
            $grandTotal = $subtotal + $vatAmount - $discount;

            $invoice = Invoice::create(array_merge(
                \Illuminate\Support\Arr::except($validated, ['items']),
                [
                    'code' => $code,
                    'subtotal' => $subtotal,
                    'vat_amount' => $vatAmount,
                    'grand_total' => $grandTotal,
                    'created_by' => auth()->id(),
                ]
            ));

            foreach ($validated['items'] as $idx => $item) {
                $invoice->lineItems()->create(array_merge($item, [
                    'total' => $item['quantity'] * $item['unit_rate'],
                    'sequence' => $item['sequence'] ?? $idx,
                ]));
            }

            return $invoice;
        });

        // Post journal entry via observer or directly
        $this->accounting->postInvoiceCreated($invoice->fresh(['client']));

        return redirect()->route('accounts.invoices.show', $invoice)->with('success', 'Invoice created.');
    }

    public function show(Invoice $invoice): Response
    {
        $this->authorize('view', $invoice);

        $invoice->load(['client', 'project', 'lineItems', 'receipts.accountHead', 'createdBy']);

        return Inertia::render('Accounts/Invoices/Show', [
            'invoice' => $invoice,
            'accountHeads' => AccountHead::whereHas('group', fn($q) => $q->where('type', 'asset'))
                ->where('is_active', true)->select('id', 'name', 'code')->get(),
        ]);
    }

    public function edit(Invoice $invoice): Response
    {
        $this->authorize('update', $invoice);
        $invoice->load('lineItems');
        return Inertia::render('Accounts/Invoices/Edit', [
            'invoice' => $invoice,
            'clients' => Client::where('is_active', true)->select('id', 'name', 'code')->get(),
            'projects' => Project::whereNotIn('status', ['completed', 'cancelled'])->select('id', 'name', 'code')->get(),
        ]);
    }

    public function update(Request $request, Invoice $invoice): RedirectResponse
    {
        $this->authorize('update', $invoice);

        abort_if($invoice->status === 'paid', 403, 'Cannot edit a paid invoice.');

        $validated = $request->validate([
            'due_date' => 'required|date',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'status' => 'required|in:draft,sent,cancelled',
        ]);

        $invoice->update($validated);

        return back()->with('success', 'Invoice updated.');
    }

    public function destroy(Invoice $invoice): RedirectResponse
    {
        $this->authorize('delete', $invoice);
        $invoice->delete();
        return redirect()->route('accounts.invoices.index')->with('success', 'Invoice deleted.');
    }

    public function pdf(Invoice $invoice)
    {
        $this->authorize('view', $invoice);
        $invoice->load(['client', 'lineItems']);

        $pdf = Pdf::loadView('pdf.invoice', ['invoice' => $invoice]);
        return $pdf->stream("INV-{$invoice->code}.pdf");
    }
}
