<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreQuotationRequest;
use App\Http\Requests\UpdateQuotationRequest;
use App\Models\Booking;
use App\Models\Customer;
use App\Models\Quotation;
use App\Models\Space;
use App\Services\BookingService;
use App\Services\InvoiceService;
use App\Services\PdfService;
use App\Services\QuotationConversionService;
use App\Services\QuotationService;
use App\Services\SettingsService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;

class QuotationController extends Controller
{
    public function index(Request $request): View
    {
        $this->authorize('viewAny', Quotation::class);

        $quotations = Quotation::query()
            ->with(['customer', 'booking'])
            ->when($request->filled('search'), function ($query) use ($request): void {
                $search = $request->string('search')->toString();
                $query->where(function ($builder) use ($search): void {
                    $builder->where('quotation_number', 'like', "%{$search}%")
                        ->orWhereHas('customer', fn ($q) => $q->where('name', 'like', "%{$search}%"));
                });
            })
            ->when($request->filled('status'), fn ($query) => $query->where('status', $request->string('status')))
            ->latest()
            ->paginate(15)
            ->withQueryString();

        return view('quotations.index', compact('quotations'));
    }

    public function create(Request $request): View
    {
        $this->authorize('create', Quotation::class);

        $customers = Customer::query()->where('is_active', true)->orderBy('name')->get();
        $spaces = Space::query()->with('layouts')->orderBy('name')->get();
        $packages = \App\Models\Package::query()
            ->where('status', \App\Enums\PackageStatus::Active)
            ->orderBy('name')
            ->get();
        $eventTypes = \App\Models\EventType::query()->where('is_active', true)->orderBy('sort_order')->get();
        $coordinators = \App\Models\User::query()->where('is_active', true)->orderBy('name')->get();
        $booking = $request->filled('booking_id')
            ? Booking::query()->with(['customer', 'spaces.space.layouts'])->find($request->integer('booking_id'))
            : null;

        return view('quotations.create', compact('customers', 'spaces', 'packages', 'booking', 'eventTypes', 'coordinators'));
    }

    public function store(StoreQuotationRequest $request, QuotationService $quotationService, BookingService $bookingService): RedirectResponse
    {
        $this->authorize('create', Quotation::class);

        $validated = $request->validated();

        try {
            $quotation = DB::transaction(function () use ($validated, $quotationService, $bookingService): Quotation {
                if (empty($validated['guest_count']) && ! empty($validated['spaces'])) {
                    $validated['guest_count'] = (int) collect($validated['spaces'])->max(
                        fn ($space) => (int) ($space['guest_count'] ?? 0)
                    );
                }

                if (empty($validated['booking_id']) && ! empty($validated['spaces'])) {
                    $booking = $bookingService->createFromDocumentPayload($validated);
                    $validated['booking_id'] = $booking->id;
                }

                foreach ([
                    'spaces', 'event_name', 'event_type_id', 'description', 'event_start', 'event_end',
                    'contact_name', 'contact_phone', 'contact_email', 'seating_arrangement',
                    'coordinator_id', 'customer_notes', 'internal_notes',
                    'space_id', 'setup_start', 'breakdown_end',
                ] as $key) {
                    unset($validated[$key]);
                }

                return $quotationService->createDraft($validated);
            });
        } catch (\App\Exceptions\DocumentException $e) {
            return back()->withInput()->with('error', $e->getMessage());
        } catch (\DomainException $e) {
            return back()->withInput()->with('error', $e->getMessage());
        }

        return redirect()
            ->route('quotations.show', $quotation)
            ->with('success', 'Quotation created successfully.');
    }

    public function show(Quotation $quotation): View
    {
        $this->authorize('view', $quotation);

        $quotation->load(['items', 'customer', 'booking.spaces.space.layouts', 'booking.eventType', 'booking.coordinator', 'convertedInvoice', 'attachments.uploader']);

        return view('quotations.show', compact('quotation'));
    }

    public function edit(Quotation $quotation): View
    {
        $this->authorize('update', $quotation);

        $quotation->load(['items', 'booking.spaces.space']);
        $customers = Customer::query()->where('is_active', true)->orderBy('name')->get();
        $spaces = Space::query()->with('layouts')->orderBy('name')->get();
        $packages = \App\Models\Package::query()
            ->where('status', \App\Enums\PackageStatus::Active)
            ->orderBy('name')
            ->get();

        return view('quotations.edit', compact('quotation', 'customers', 'spaces', 'packages'));
    }

    public function update(UpdateQuotationRequest $request, Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('update', $quotation);

        $quotationService->updateDraft($quotation, $request->validated());

        return redirect()
            ->route('quotations.show', $quotation)
            ->with('success', 'Quotation updated successfully.');
    }

    public function destroy(Quotation $quotation): RedirectResponse
    {
        $this->authorize('delete', $quotation);

        $quotation->items()->delete();
        $quotation->delete();

        return redirect()
            ->route('quotations.index')
            ->with('success', 'Quotation deleted successfully.');
    }

    public function createFromBooking(Booking $booking, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('create', Quotation::class);

        $quotation = $quotationService->createFromBooking($booking);

        return redirect()
            ->route('quotations.show', $quotation)
            ->with('success', 'Quotation created from booking.');
    }

    public function issue(Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('issue', $quotation);

        $quotationService->issue($quotation);

        return back()->with('success', 'Quotation issued successfully.');
    }

    public function accept(Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('accept', $quotation);

        $quotationService->accept($quotation);

        return back()->with('success', 'Quotation accepted.');
    }

    public function reject(Request $request, Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('update', $quotation);

        $quotationService->reject($quotation, $request->string('reason')->toString() ?: null);

        return back()->with('success', 'Quotation rejected.');
    }

    public function expire(Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('update', $quotation);

        $quotationService->expire($quotation);

        return back()->with('success', 'Quotation marked as expired.');
    }

    public function cancel(Request $request, Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('update', $quotation);

        $quotationService->cancel($quotation, $request->string('reason')->toString() ?: null);

        return back()->with('success', 'Quotation cancelled.');
    }

    public function revise(Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('update', $quotation);

        $revision = $quotationService->revise($quotation);

        return redirect()
            ->route('quotations.edit', $revision)
            ->with('success', 'New quotation revision created.');
    }

    public function duplicate(Quotation $quotation, QuotationService $quotationService): RedirectResponse
    {
        $this->authorize('create', Quotation::class);

        $copy = $quotationService->duplicate($quotation);

        return redirect()
            ->route('quotations.show', $copy)
            ->with('success', 'Quotation duplicated.');
    }

    public function convert(Quotation $quotation, QuotationConversionService $conversionService): RedirectResponse
    {
        $this->authorize('convert', $quotation);

        $invoice = $conversionService->convert($quotation);

        return redirect()
            ->route('invoices.show', $invoice)
            ->with('success', 'Quotation converted to invoice.');
    }

    public function pdf(Quotation $quotation, PdfService $pdfService)
    {
        $this->authorize('view', $quotation);

        return $pdfService->quotation($quotation);
    }

    public function print(Quotation $quotation, SettingsService $settings): View
    {
        $this->authorize('view', $quotation);

        $quotation->load(['items', 'customer', 'booking']);

        return view('pdf.quotation-print', [
            'quotation' => $quotation,
            'settings' => $settings->all(),
        ]);
    }
}
