<?php

namespace App\Http\Controllers;

use App\Enums\SpaceOperationalStatus;
use App\Enums\ReservationStatus;
use App\Http\Requests\StoreSpaceBlockRequest;
use App\Http\Requests\StoreSpaceRequest;
use App\Http\Requests\UpdateSpaceRequest;
use App\Models\BookingSpace;
use App\Models\Space;
use App\Models\SpaceBlock;
use App\Models\SpaceType;
use App\Services\AuditService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;

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

        $spaces = Space::query()
            ->with('spaceType')
            ->when($request->filled('search'), function ($query) use ($request): void {
                $search = $request->string('search')->toString();
                $query->where(function ($builder) use ($search): void {
                    $builder->where('name', 'like', "%{$search}%")
                        ->orWhere('code', 'like', "%{$search}%")
                        ->orWhere('location', 'like', "%{$search}%");
                });
            })
            ->when($request->filled('space_type_id'), fn ($query) => $query->where('space_type_id', $request->integer('space_type_id')))
            ->when($request->filled('operational_status'), fn ($query) => $query->where('operational_status', $request->string('operational_status')))
            ->latest()
            ->paginate(15)
            ->withQueryString();

        $spaceTypes = SpaceType::query()->orderBy('name')->get();

        return view('spaces.index', compact('spaces', 'spaceTypes'));
    }

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

        $spaceTypes = SpaceType::query()->where('is_active', true)->orderBy('name')->get();

        return view('spaces.create', compact('spaceTypes'));
    }

    public function store(StoreSpaceRequest $request, AuditService $auditService): RedirectResponse
    {
        $this->authorize('create', Space::class);

        $validated = $request->validated();
        $layouts = $validated['layouts'] ?? [];
        unset($validated['layouts']);

        $space = DB::transaction(function () use ($validated, $layouts): Space {
            $space = Space::query()->create($validated);

            foreach ($layouts as $index => $layout) {
                $space->layouts()->create([
                    'layout_name' => $layout['layout_name'],
                    'capacity' => $layout['capacity'],
                    'is_custom' => $layout['is_custom'] ?? false,
                    'sort_order' => $layout['sort_order'] ?? $index,
                ]);
            }

            return $space->load(['spaceType', 'layouts']);
        });

        $auditService->log('space.created', $space, null, $space->toArray());

        return redirect()
            ->route('spaces.show', $space)
            ->with('success', 'Space created successfully.');
    }

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

        $space->load(['spaceType', 'layouts', 'images', 'blocks.creator']);

        $upcomingReservations = BookingSpace::query()
            ->with(['booking.customer', 'booking'])
            ->where('space_id', $space->id)
            ->whereIn('reservation_status', [ReservationStatus::Provisional, ReservationStatus::Confirmed])
            ->where('event_start', '>=', now())
            ->orderBy('event_start')
            ->limit(50)
            ->get();

        return view('spaces.show', compact('space', 'upcomingReservations'));
    }

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

        $space->load('layouts');
        $spaceTypes = SpaceType::query()->where('is_active', true)->orderBy('name')->get();

        return view('spaces.edit', compact('space', 'spaceTypes'));
    }

    public function update(UpdateSpaceRequest $request, Space $space, AuditService $auditService): RedirectResponse
    {
        $this->authorize('update', $space);

        $validated = $request->validated();
        $layouts = $validated['layouts'] ?? null;
        unset($validated['layouts']);

        $oldValues = $space->loadMissing('layouts')->toArray();
        $oldLayouts = $space->layouts->map(fn ($layout) => [
            'layout_name' => $layout->layout_name,
            'capacity' => $layout->capacity,
            'is_custom' => $layout->is_custom,
            'sort_order' => $layout->sort_order,
        ])->values()->all();

        DB::transaction(function () use ($space, $validated, $layouts): void {
            $space->update($validated);

            if ($layouts !== null) {
                $space->layouts()->delete();

                foreach ($layouts as $index => $layout) {
                    $space->layouts()->create([
                        'layout_name' => $layout['layout_name'],
                        'capacity' => $layout['capacity'],
                        'is_custom' => $layout['is_custom'] ?? false,
                        'sort_order' => $layout['sort_order'] ?? $index,
                    ]);
                }
            }
        });

        $space->refresh()->load(['spaceType', 'layouts']);

        $auditService->log('space.updated', $space, $oldValues, $space->toArray());

        if ($layouts !== null) {
            $auditService->log(
                'space.layouts_updated',
                $space,
                ['layouts' => $oldLayouts],
                ['layouts' => $space->layouts->map(fn ($layout) => [
                    'layout_name' => $layout->layout_name,
                    'capacity' => $layout->capacity,
                    'is_custom' => $layout->is_custom,
                    'sort_order' => $layout->sort_order,
                ])->values()->all()],
                'Space seating layouts replaced.',
            );
        }

        return redirect()
            ->route('spaces.show', $space)
            ->with('success', 'Space updated successfully.');
    }

    public function destroy(Space $space, AuditService $auditService): RedirectResponse
    {
        $this->authorize('delete', $space);

        $oldValues = $space->toArray();

        $space->update(['operational_status' => SpaceOperationalStatus::Archived]);
        $space->delete();

        $auditService->log('space.archived', $space, $oldValues);

        return redirect()
            ->route('spaces.index')
            ->with('success', 'Space archived successfully.');
    }

    public function storeBlock(StoreSpaceBlockRequest $request, Space $space, AuditService $auditService): RedirectResponse
    {
        $this->authorize('block', $space);

        $block = SpaceBlock::query()->create([
            ...$request->validated(),
            'space_id' => $space->id,
            'created_by' => $request->user()?->id,
        ]);

        $auditService->log('space_block.created', $block, null, $block->toArray());

        return redirect()
            ->route('spaces.show', $space)
            ->with('success', 'Space block created successfully.');
    }
}
