<?php

namespace App\Http\Controllers;

use App\Models\Client;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Barryvdh\DomPDF\Facade\Pdf;

class InvoiceController extends Controller
{
    // ─────────────────────────────────────────
    // LIST
    // ─────────────────────────────────────────
    public function index(Request $request)
    {
        $user  = Auth::user();
        $query = $user->invoices()->with('client')->latest();

        // Filter by status
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        // Search by client name or invoice number
        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('invoice_number', 'like', "%{$search}%")
                  ->orWhereHas('client', fn($c) => $c->where('name', 'like', "%{$search}%")
                      ->orWhere('business_name', 'like', "%{$search}%"));
            });
        }

        $invoices = $query->paginate(15)->withQueryString();

        // Status counts for filter tabs
        $statusCounts = $user->invoices()
            ->selectRaw('status, count(*) as count')
            ->groupBy('status')
            ->pluck('count', 'status');

        return view('invoices.index', compact('invoices', 'statusCounts'));
    }

    // ─────────────────────────────────────────
    // CREATE
    // ─────────────────────────────────────────
    public function create()
    {
        $user = Auth::user();

        // Check free plan limit
        if ($user->hasReachedInvoiceLimit()) {
            return redirect()->route('settings.subscription')
                ->with('error', 'You have reached your monthly invoice limit. Please upgrade to continue.');
        }

        $clients = $user->clients()->orderBy('name')->get();

        return view('invoices.create', compact('clients'));
    }

    // ─────────────────────────────────────────
    // STORE
    // ─────────────────────────────────────────
    public function store(Request $request)
    {
        $user = Auth::user();

        if ($user->hasReachedInvoiceLimit()) {
            return back()->with('error', 'Monthly invoice limit reached. Please upgrade your plan.');
        }

        $data = $request->validate([
            'client_id'    => ['required', 'exists:clients,id'],
            'issue_date'   => ['required', 'date'],
            'due_date'     => ['required', 'date', 'after_or_equal:issue_date'],
            'vat_rate'     => ['nullable', 'numeric', 'min:0', 'max:100'],
            'discount'     => ['nullable', 'numeric', 'min:0'],
            'notes'        => ['nullable', 'string', 'max:1000'],
            'status'       => ['required', 'in:draft,sent'],
            'items'        => ['required', 'array', 'min:1'],
            'items.*.description' => ['required', 'string', 'max:500'],
            'items.*.quantity'    => ['required', 'numeric', 'min:0.01'],
            'items.*.unit_price'  => ['required', 'numeric', 'min:0'],
        ]);

        // Verify client belongs to this user
        $client = $user->clients()->findOrFail($data['client_id']);

        DB::transaction(function () use ($data, $user, $client, $request) {
            $invoiceNumber = $user->generateInvoiceNumber();

            // Calculate totals
            $subtotal  = collect($data['items'])->sum(fn($i) => $i['quantity'] * $i['unit_price']);
            $vatRate   = $data['vat_rate'] ?? 7.5;
            $vatAmount = round($subtotal * ($vatRate / 100), 2);
            $discount  = $data['discount'] ?? 0;
            $total     = max(0, $subtotal + $vatAmount - $discount);

            $invoice = $user->invoices()->create([
                'client_id'      => $client->id,
                'invoice_number' => $invoiceNumber,
                'status'         => $data['status'],
                'issue_date'     => $data['issue_date'],
                'due_date'       => $data['due_date'],
                'subtotal'       => $subtotal,
                'vat_rate'       => $vatRate,
                'vat_amount'     => $vatAmount,
                'discount'       => $discount,
                'total'          => $total,
                'notes'          => $data['notes'] ?? null,
                'sent_at'        => $data['status'] === 'sent' ? now() : null,
            ]);

            // Create line items
            foreach ($data['items'] as $index => $item) {
                $invoice->items()->create([
                    'description' => $item['description'],
                    'quantity'    => $item['quantity'],
                    'unit_price'  => $item['unit_price'],
                    'total'       => $item['quantity'] * $item['unit_price'],
                    'sort_order'  => $index,
                ]);
            }

            // Update client totals
            $client->recalculateTotals();

            // Send email if status is 'sent'
            if ($data['status'] === 'sent' && $client->email) {
                try {
                    Mail::to($client->email)->send(new \App\Mail\InvoiceSent($invoice));
                } catch (\Exception $e) {
                    // Log but don't fail the request
                    \Log::error('Invoice email failed: ' . $e->getMessage());
                }
            }

            session()->flash('success', "Invoice {$invoice->invoice_number} created successfully.");
            session()->flash('new_invoice_id', $invoice->id);
        });

        return redirect()->route('invoices.index')
            ->with('success', 'Invoice created successfully.');
    }

    // ─────────────────────────────────────────
    // SHOW
    // ─────────────────────────────────────────
    public function show(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);
        $invoice->load(['client', 'items', 'payments']);

        return view('invoices.show', compact('invoice'));
    }

    // ─────────────────────────────────────────
    // EDIT
    // ─────────────────────────────────────────
    public function edit(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);

        if (! $invoice->isEditable()) {
            return redirect()->route('invoices.show', $invoice)
                ->with('error', 'Only draft invoices can be edited.');
        }

        $clients = Auth::user()->clients()->orderBy('name')->get();
        $invoice->load('items');

        return view('invoices.edit', compact('invoice', 'clients'));
    }

    // ─────────────────────────────────────────
    // UPDATE
    // ─────────────────────────────────────────
    public function update(Request $request, Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);

        if (! $invoice->isEditable()) {
            return back()->with('error', 'Only draft invoices can be edited.');
        }

        $data = $request->validate([
            'client_id'    => ['required', 'exists:clients,id'],
            'issue_date'   => ['required', 'date'],
            'due_date'     => ['required', 'date', 'after_or_equal:issue_date'],
            'vat_rate'     => ['nullable', 'numeric', 'min:0', 'max:100'],
            'discount'     => ['nullable', 'numeric', 'min:0'],
            'notes'        => ['nullable', 'string', 'max:1000'],
            'items'        => ['required', 'array', 'min:1'],
            'items.*.description' => ['required', 'string', 'max:500'],
            'items.*.quantity'    => ['required', 'numeric', 'min:0.01'],
            'items.*.unit_price'  => ['required', 'numeric', 'min:0'],
        ]);

        DB::transaction(function () use ($data, $invoice) {
            $subtotal  = collect($data['items'])->sum(fn($i) => $i['quantity'] * $i['unit_price']);
            $vatRate   = $data['vat_rate'] ?? 7.5;
            $vatAmount = round($subtotal * ($vatRate / 100), 2);
            $discount  = $data['discount'] ?? 0;
            $total     = max(0, $subtotal + $vatAmount - $discount);

            $invoice->update([
                'client_id'  => $data['client_id'],
                'issue_date' => $data['issue_date'],
                'due_date'   => $data['due_date'],
                'subtotal'   => $subtotal,
                'vat_rate'   => $vatRate,
                'vat_amount' => $vatAmount,
                'discount'   => $discount,
                'total'      => $total,
                'notes'      => $data['notes'] ?? null,
            ]);

            // Replace all line items
            $invoice->items()->delete();
            foreach ($data['items'] as $index => $item) {
                $invoice->items()->create([
                    'description' => $item['description'],
                    'quantity'    => $item['quantity'],
                    'unit_price'  => $item['unit_price'],
                    'total'       => $item['quantity'] * $item['unit_price'],
                    'sort_order'  => $index,
                ]);
            }

            $invoice->client->recalculateTotals();
        });

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

    // ─────────────────────────────────────────
    // SEND EMAIL
    // ─────────────────────────────────────────
    public function send(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);

        if (! $invoice->canBeSent()) {
            return back()->with('error', 'This invoice cannot be sent.');
        }

        if (! $invoice->client->email) {
            return back()->with('error', 'This client has no email address. Please update their profile first.');
        }

        try {
            Mail::to($invoice->client->email)->send(new \App\Mail\InvoiceSent($invoice));

            $invoice->update([
                'status'  => 'sent',
                'sent_at' => now(),
            ]);

            return back()->with('success', "Invoice sent to {$invoice->client->email} successfully.");
        } catch (\Exception $e) {
            return back()->with('error', 'Failed to send email. Please check your mail settings.');
        }
    }

    // ─────────────────────────────────────────
    // DOWNLOAD PDF
    // ─────────────────────────────────────────
    public function download(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);
        $invoice->load(['client', 'items', 'user']);

        $pdf = Pdf::loadView('invoices.pdf', compact('invoice'))
            ->setPaper('a4', 'portrait');

        return $pdf->download($invoice->invoice_number . '.pdf');
    }

    // ─────────────────────────────────────────
    // MARK PAID (manual)
    // ─────────────────────────────────────────
    public function markPaid(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);

        if (! $invoice->canBeMarkedPaid()) {
            return back()->with('error', 'This invoice cannot be marked as paid.');
        }

        DB::transaction(function () use ($invoice) {
            $invoice->update([
                'status'  => 'paid',
                'paid_at' => now(),
            ]);

            Payment::create([
                'invoice_id'     => $invoice->id,
                'amount'         => $invoice->total,
                'payment_method' => 'bank_transfer',
                'paid_at'        => now(),
            ]);

            $invoice->client->recalculateTotals();
        });

        return back()->with('success', "Invoice {$invoice->invoice_number} marked as paid.");
    }

    // ─────────────────────────────────────────
    // DUPLICATE
    // ─────────────────────────────────────────
    public function duplicate(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);
        $invoice->load('items');

        $user          = Auth::user();
        $invoiceNumber = $user->generateInvoiceNumber();

        DB::transaction(function () use ($invoice, $user, $invoiceNumber) {
            $newInvoice = $user->invoices()->create([
                'client_id'      => $invoice->client_id,
                'invoice_number' => $invoiceNumber,
                'status'         => 'draft',
                'issue_date'     => now()->toDateString(),
                'due_date'       => now()->addDays($user->payment_terms)->toDateString(),
                'subtotal'       => $invoice->subtotal,
                'vat_rate'       => $invoice->vat_rate,
                'vat_amount'     => $invoice->vat_amount,
                'discount'       => $invoice->discount,
                'total'          => $invoice->total,
                'notes'          => $invoice->notes,
            ]);

            foreach ($invoice->items as $item) {
                $newInvoice->items()->create([
                    'description' => $item->description,
                    'quantity'    => $item->quantity,
                    'unit_price'  => $item->unit_price,
                    'total'       => $item->total,
                    'sort_order'  => $item->sort_order,
                ]);
            }

            session()->flash('new_invoice_id', $newInvoice->id);
        });

        return redirect()->route('invoices.index')
            ->with('success', "Invoice duplicated as {$invoiceNumber}.");
    }

    // ─────────────────────────────────────────
    // CANCEL
    // ─────────────────────────────────────────
    public function cancel(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);

        if ($invoice->isPaid() || $invoice->isCancelled()) {
            return back()->with('error', 'This invoice cannot be cancelled.');
        }

        $invoice->update(['status' => 'cancelled']);
        $invoice->client->recalculateTotals();

        return back()->with('success', "Invoice {$invoice->invoice_number} has been cancelled.");
    }

    // ─────────────────────────────────────────
    // DELETE (draft only)
    // ─────────────────────────────────────────
    public function destroy(Invoice $invoice)
    {
        $this->authorizeInvoice($invoice);

        if (! $invoice->isDraft()) {
            return back()->with('error', 'Only draft invoices can be deleted.');
        }

        $client = $invoice->client;
        $number = $invoice->invoice_number;
        $invoice->delete();
        $client->recalculateTotals();

        return redirect()->route('invoices.index')
            ->with('success', "Invoice {$number} deleted.");
    }

    // ─────────────────────────────────────────
    // PUBLIC PAGE (no auth — client payment link)
    // ─────────────────────────────────────────
    public function public(string $token)
    {
        $invoice = Invoice::where('public_token', $token)
            ->with(['client', 'items', 'user'])
            ->firstOrFail();

        // Mark as viewed if it was only sent
        if ($invoice->status === 'sent') {
            $invoice->update(['status' => 'viewed', 'viewed_at' => now()]);
        }

        $paystackPublicKey = config('invotrack.paystack.public_key');

        return view('invoices.public', compact('invoice', 'paystackPublicKey'));
    }

    // ─────────────────────────────────────────
    // PRIVATE HELPER
    // ─────────────────────────────────────────
    private function authorizeInvoice(Invoice $invoice): void
    {
        if ($invoice->user_id !== Auth::id()) {
            abort(403, 'Unauthorized');
        }
    }
}
