<?php

namespace App\Http\Controllers\Admin;

use App\Enums\InvoiceStatus;
use App\Enums\PaymentStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreInvoiceRequest;
use App\Http\Requests\UpdateInvoiceRequest;
use App\Models\Appointment;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Service;
use App\Services\Billing\InvoicePdfService;
use App\Services\Billing\InvoiceService;
use App\Services\Billing\PaymentRecordService;
use App\Services\Tenancy\CurrentBusiness;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

class InvoiceController extends Controller
{
    public function index(Request $request, CurrentBusiness $currentBusiness): View
    {
        $business = $currentBusiness->get() ?? abort(403);
        $filters = $request->only(['q', 'status', 'customer_id', 'date_from', 'date_to', 'amount', 'sort']);

        $invoicesQuery = Invoice::query()
            ->forBusiness($business)
            ->with(['customer', 'items.service'])
            ->withCount('payments')
            ->when($filters['q'] ?? null, function (Builder $query, string $search): void {
                $query->where(function (Builder $query) use ($search): void {
                    $query->where('invoice_number', 'like', "%{$search}%")
                        ->orWhereHas('customer', function (Builder $customerQuery) use ($search): void {
                            $customerQuery->where('name', 'like', "%{$search}%")
                                ->orWhere('email', 'like', "%{$search}%")
                                ->orWhere('phone', 'like', "%{$search}%");
                        })
                        ->orWhereHas('items', fn (Builder $itemQuery) => $itemQuery->where('description', 'like', "%{$search}%"));
                });
            })
            ->when($filters['status'] ?? null, fn (Builder $query, string $status) => $query->where('status', $status))
            ->when($filters['customer_id'] ?? null, fn (Builder $query, string $customerId) => $query->where('customer_id', $customerId))
            ->when($filters['date_from'] ?? null, fn (Builder $query, string $date) => $query->whereDate('issue_date', '>=', $date))
            ->when($filters['date_to'] ?? null, fn (Builder $query, string $date) => $query->whereDate('issue_date', '<=', $date))
            ->when($filters['amount'] ?? null, function (Builder $query, string $amount): void {
                match ($amount) {
                    'under_100' => $query->where('total', '<', 100),
                    '100_500' => $query->whereBetween('total', [100, 500]),
                    'over_500' => $query->where('total', '>', 500),
                    default => null,
                };
            });

        match ($filters['sort'] ?? 'newest') {
            'oldest' => $invoicesQuery->oldest('issue_date'),
            'due_soon' => $invoicesQuery->orderBy('due_date'),
            'amount_desc' => $invoicesQuery->orderByDesc('total'),
            'balance_desc' => $invoicesQuery->orderByDesc('balance_due'),
            default => $invoicesQuery->latest('issue_date')->latest(),
        };

        $invoices = $invoicesQuery->paginate(10)->withQueryString();
        $baseQuery = Invoice::query()->forBusiness($business);

        return view('admin.invoices.index', [
            'invoices' => $invoices,
            'filters' => $filters,
            'customers' => Customer::query()->forBusiness($business)->orderBy('name')->get(),
            'statusOptions' => InvoiceStatus::options(),
            'paymentMethods' => PaymentRecordService::methods(),
            'stats' => [
                'total' => (clone $baseQuery)->count(),
                'this_month' => (clone $baseQuery)->whereBetween('issue_date', [now()->startOfMonth(), now()->endOfMonth()])->count(),
                'paid_revenue' => Payment::query()->forBusiness($business)->where('status', PaymentStatus::Paid->value)->sum('amount'),
                'outstanding' => (clone $baseQuery)->whereNot('status', InvoiceStatus::Cancelled->value)->sum('balance_due'),
                'due_count' => (clone $baseQuery)->where('balance_due', '>', 0)->whereNot('status', InvoiceStatus::Cancelled->value)->count(),
                'overdue_count' => (clone $baseQuery)->where('status', InvoiceStatus::Overdue->value)->count(),
                'overdue_total' => (clone $baseQuery)->where('status', InvoiceStatus::Overdue->value)->sum('balance_due'),
            ],
        ]);
    }

    public function create(CurrentBusiness $currentBusiness, InvoiceService $invoiceService): View
    {
        $business = $currentBusiness->get() ?? abort(403);

        return view('admin.invoices.create', [
            ...$this->formData($business->id),
            'invoice' => new Invoice([
                'invoice_number' => $invoiceService->nextInvoiceNumber($business),
                'status' => InvoiceStatus::Draft->value,
                'issue_date' => now(),
                'due_date' => now()->addDays(7),
                'currency' => $business->currency ?: 'USD',
                'discount_total' => 0,
                'footer_note' => 'Thank you for choosing '.$business->name.'.',
            ]),
            'formAction' => route('admin.invoices.store'),
            'formMethod' => 'POST',
            'submitLabel' => 'Create Invoice',
        ]);
    }

    public function store(StoreInvoiceRequest $request, CurrentBusiness $currentBusiness, InvoiceService $invoiceService): RedirectResponse
    {
        $business = $currentBusiness->get() ?? abort(403);
        $invoice = $invoiceService->create($business, $request->payload());

        return redirect()
            ->route('admin.invoices.show', $invoice)
            ->with('status', 'Invoice created successfully.');
    }

    public function show(Invoice $invoice, CurrentBusiness $currentBusiness): View
    {
        $this->authorizeInvoice($invoice, $currentBusiness);
        $invoice->load(['business', 'customer', 'appointment.service', 'items.service', 'payments' => fn ($query) => $query->latest('paid_at')->latest()]);

        return view('admin.invoices.show', [
            'invoice' => $invoice,
            'statusOptions' => InvoiceStatus::options(),
            'paymentMethods' => PaymentRecordService::methods(),
        ]);
    }

    public function edit(Invoice $invoice, CurrentBusiness $currentBusiness): View
    {
        $business = $this->authorizeInvoice($invoice, $currentBusiness);
        $invoice->load(['items.service', 'customer']);

        return view('admin.invoices.edit', [
            ...$this->formData($business->id),
            'invoice' => $invoice,
            'formAction' => route('admin.invoices.update', $invoice),
            'formMethod' => 'PUT',
            'submitLabel' => 'Update Invoice',
        ]);
    }

    public function update(UpdateInvoiceRequest $request, Invoice $invoice, CurrentBusiness $currentBusiness, InvoiceService $invoiceService): RedirectResponse
    {
        $business = $this->authorizeInvoice($invoice, $currentBusiness);
        $invoice = $invoiceService->update($business, $invoice, $request->payload());

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

    public function destroy(Invoice $invoice, CurrentBusiness $currentBusiness, InvoiceService $invoiceService): RedirectResponse
    {
        $business = $this->authorizeInvoice($invoice, $currentBusiness);
        $invoiceService->delete($business, $invoice);

        return redirect()
            ->route('admin.invoices.index')
            ->with('status', 'Invoice deleted successfully.');
    }

    public function pdf(Invoice $invoice, CurrentBusiness $currentBusiness, InvoicePdfService $pdfService): Response
    {
        $this->authorizeInvoice($invoice, $currentBusiness);
        $invoice->load(['business', 'customer', 'items.service', 'payments']);

        return response($pdfService->make($invoice), 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'inline; filename="'.$invoice->invoice_number.'.pdf"',
        ]);
    }

    private function authorizeInvoice(Invoice $invoice, CurrentBusiness $currentBusiness)
    {
        $business = $currentBusiness->get() ?? abort(403);

        abort_unless((int) $invoice->business_id === (int) $business->id, 404);

        return $business;
    }

    private function formData(int $businessId): array
    {
        return [
            'customers' => Customer::query()->forBusiness($businessId)->orderBy('name')->get(),
            'appointments' => Appointment::query()
                ->forBusiness($businessId)
                ->with(['customer', 'service', 'staffProfile'])
                ->latest('starts_at')
                ->limit(100)
                ->get(),
            'services' => Service::query()->forBusiness($businessId)->orderBy('name')->get(),
            'statusOptions' => InvoiceStatus::options(),
        ];
    }
}
