<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreInvoiceRequest;
use App\Http\Requests\Admin\UpdateInvoiceRequest;
use App\Models\AuditLog;
use App\Models\Invoice;
use App\Models\User;
use App\Notifications\InvoiceNotification;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Inertia\Inertia;
use Inertia\Response;

class InvoiceController extends Controller
{
    public function index(Request $request): Response
    {
        $query = Invoice::query()
            ->with('user:id,name,email');

        // Search by invoice number or customer name
        if ($search = $request->input('search')) {
            $query->where(function ($q) use ($search): void {
                $q->where('number', 'like', "%{$search}%")
                    ->orWhereHas('user', function ($uq) use ($search): void {
                        $uq->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    });
            });
        }

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

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

        return Inertia::render('Admin/Invoices/Index', [
            'invoices' => $invoices,
            'filters' => [
                'search' => $request->input('search', ''),
                'status' => $request->input('status', ''),
            ],
        ]);
    }

    public function create(): Response
    {
        $customers = User::query()
            ->select('id', 'name', 'email')
            ->orderBy('name')
            ->get();

        return Inertia::render('Admin/Invoices/Create', [
            'customers' => $customers,
        ]);
    }

    public function store(StoreInvoiceRequest $request): RedirectResponse
    {
        $validated = $request->validated();

        $invoice = DB::transaction(function () use ($validated, $request): Invoice {
            // Calculate total from line items
            $total = collect($validated['items'])->sum(function (array $item): float {
                return (float) $item['unit_price'] * (int) $item['quantity'];
            });

            // Generate unique invoice number
            $number = 'INV-'.now()->format('Ymd').'-'.strtoupper(Str::random(6));

            $status = ($validated['send_immediately'] ?? false) ? 'pending' : 'draft';

            $invoice = Invoice::create([
                'user_id' => $validated['customer_id'],
                'gateway' => 'manual',
                'number' => $number,
                'total' => $total,
                'tax' => 0,
                'currency' => 'USD',
                'status' => $status,
                'due_date' => $validated['due_date'],
                'notes' => $validated['notes'] ?? null,
            ]);

            // Create line items
            foreach ($validated['items'] as $item) {
                $invoice->items()->create([
                    'description' => $item['description'],
                    'quantity' => $item['quantity'],
                    'amount' => $item['unit_price'],
                ]);
            }

            AuditLog::create([
                'user_id' => $validated['customer_id'],
                'admin_id' => $request->user()?->id,
                'action' => 'create_invoice',
                'resource_type' => 'invoice',
                'resource_id' => $invoice->id,
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
            ]);

            return $invoice;
        });

        // Send email if requested
        if ($validated['send_immediately'] ?? false) {
            $invoice->load('user');
            $invoice->user?->notify(new InvoiceNotification($invoice));
        }

        return redirect()->route('invoices.show', $invoice)
            ->with('success', "Invoice {$invoice->number} has been created.");
    }

    public function show(Invoice $invoice): Response
    {
        $invoice->load([
            'user:id,name,email,status',
            'items',
            'paymentTransactions',
        ]);

        return Inertia::render('Admin/Invoices/Show', [
            'invoice' => $invoice,
        ]);
    }

    public function edit(Invoice $invoice): Response|RedirectResponse
    {
        if (! in_array($invoice->status, ['draft', 'pending'])) {
            return redirect()->route('invoices.show', $invoice)
                ->with('error', 'Only draft or pending invoices can be edited.');
        }

        $invoice->load(['user:id,name,email', 'items']);

        return Inertia::render('Admin/Invoices/Edit', [
            'invoice' => $invoice,
        ]);
    }

    public function update(UpdateInvoiceRequest $request, Invoice $invoice): RedirectResponse
    {
        if (! in_array($invoice->status, ['draft', 'pending'])) {
            return redirect()->route('invoices.show', $invoice)
                ->with('error', 'Only draft or pending invoices can be edited.');
        }

        $validated = $request->validated();

        DB::transaction(function () use ($invoice, $validated, $request): void {
            // Delete existing items and recreate
            $invoice->items()->delete();

            $total = 0.0;
            foreach ($validated['items'] as $item) {
                $lineTotal = (float) $item['unit_price'] * (int) $item['quantity'];
                $total += $lineTotal;

                $invoice->items()->create([
                    'description' => $item['description'],
                    'quantity' => $item['quantity'],
                    'amount' => $item['unit_price'],
                ]);
            }

            $invoice->update([
                'total' => $total,
                'due_date' => $validated['due_date'],
                'notes' => $validated['notes'] ?? null,
            ]);

            AuditLog::create([
                'user_id' => $invoice->user_id,
                'admin_id' => $request->user()?->id,
                'action' => 'update_invoice',
                'resource_type' => 'invoice',
                'resource_id' => $invoice->id,
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
            ]);
        });

        return redirect()->route('invoices.show', $invoice)
            ->with('success', "Invoice {$invoice->number} has been updated.");
    }

    public function resend(Invoice $invoice): RedirectResponse
    {
        $invoice->load('user');

        if (! $invoice->user) {
            return redirect()->back()->with('error', 'Cannot resend: no customer associated with this invoice.');
        }

        $invoice->user->notify(new InvoiceNotification($invoice));

        AuditLog::create([
            'user_id' => $invoice->user_id,
            'admin_id' => auth()->id(),
            'action' => 'resend_invoice',
            'resource_type' => 'invoice',
            'resource_id' => $invoice->id,
            'ip_address' => request()->ip(),
            'user_agent' => request()->userAgent(),
        ]);

        return redirect()->back()->with('success', "Invoice {$invoice->number} email has been queued for delivery.");
    }

    public function download(Invoice $invoice): \Symfony\Component\HttpFoundation\Response
    {
        $invoice->load(['user', 'items']);

        $pdf = Pdf::loadView('pdf.invoice', ['invoice' => $invoice]);

        return $pdf->download("invoice-{$invoice->number}.pdf");
    }

    public function void(Invoice $invoice): RedirectResponse
    {
        $invoice->update(['status' => 'void']);

        AuditLog::create([
            'user_id' => $invoice->user_id,
            'admin_id' => auth()->id(),
            'action' => 'void_invoice',
            'resource_type' => 'invoice',
            'resource_id' => $invoice->id,
            'ip_address' => request()->ip(),
            'user_agent' => request()->userAgent(),
        ]);

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