<?php

namespace App\Http\Controllers\Api;

use App\Enums\ReservationSource;
use App\Enums\ReservationStatus;
use App\Events\UserNotificationsUpdated;
use App\Jobs\SendAdminNotification;
use App\Http\Controllers\Controller;
use App\Models\Listing;
use App\Models\ListingAvailability;
use App\Models\ListingSchedule;
use App\Models\Reservation;
use App\Notifications\ReservationCancelled;
use App\Notifications\ReservationCreated;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ReservationController extends Controller
{
    /**
     * Get customer's reservations
     */
    public function index(Request $request): JsonResponse
    {
        $query = $request->user()
            ->reservations()
            ->with(['listing.coverImage', 'listing.city', 'listing.owner:id,name', 'availability', 'schedule', 'review:id,reservation_id']);

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

        // Filter by date range
        if ($request->has('from_date')) {
            $query->where('reservation_date', '>=', $request->from_date);
        }

        if ($request->has('to_date')) {
            $query->where('reservation_date', '<=', $request->to_date);
        }

        $reservations = $query->latest()->paginate(15);

        return response()->json($reservations);
    }

    /**
     * Get single reservation
     */
    public function show(Reservation $reservation): JsonResponse
    {
        // Ensure user owns this reservation
        if ($reservation->user_id !== request()->user()->id) {
            return response()->json([
                'message' => 'Rezervasyon bulunamadı.',
            ], 404);
        }

        $reservation->load([
            'listing.images',
            'listing.city.province',
            'listing.owner:id,name,phone,avatar',
            'availability',
            'schedule'
        ]);

        return response()->json([
            'reservation' => $reservation,
        ]);
    }

    /**
     * Check if user has active reservations for a listing
     * Returns all active (pending/approved) reservations keyed by schedule_id
     */
    public function check(Request $request): JsonResponse
    {
        $request->validate([
            'listing_id' => ['required', 'exists:listings,id'],
        ]);

        $reservations = $request->user()
            ->reservations()
            ->where('listing_id', $request->listing_id)
            ->whereIn('status', [ReservationStatus::PENDING, ReservationStatus::APPROVED])
            ->with(['schedule', 'availability'])
            ->get();

        return response()->json([
            'reservations' => $reservations,
        ]);
    }

    /**
     * Create new reservation
     */
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'listing_id' => ['required', 'exists:listings,id'],
            'schedule_id' => ['nullable', 'exists:listing_schedules,id'],
            'availability_id' => ['nullable', 'exists:listing_availabilities,id'],
            'guest_count' => ['required', 'integer', 'min:1'],
            'customer_note' => ['nullable', 'string', 'max:500'],
        ]);

        // En az biri olmalı
        if (empty($validated['schedule_id']) && empty($validated['availability_id'])) {
            return response()->json([
                'message' => 'Tarih seçimi gerekli (schedule_id veya availability_id).',
            ], 422);
        }

        $listing = Listing::findOrFail($validated['listing_id']);

        // Validations
        if ($listing->status->value !== 'active') {
            return response()->json([
                'message' => 'Bu ilan aktif değil.',
            ], 422);
        }

        // Check capacity
        if ($validated['guest_count'] > $listing->capacity) {
            return response()->json([
                'message' => 'Misafir sayısı tekne kapasitesini aşıyor.',
            ], 422);
        }

        // Duplicate reservation check (per schedule/availability)
        $duplicateQuery = $request->user()
            ->reservations()
            ->where('listing_id', $validated['listing_id'])
            ->whereIn('status', [ReservationStatus::PENDING, ReservationStatus::APPROVED]);

        if (!empty($validated['schedule_id'])) {
            $duplicateQuery->where('listing_schedule_id', $validated['schedule_id']);
        } elseif (!empty($validated['availability_id'])) {
            $duplicateQuery->where('listing_availability_id', $validated['availability_id']);
        }

        $existingReservation = $duplicateQuery->first();

        if ($existingReservation) {
            $statusLabel = $existingReservation->status === ReservationStatus::PENDING
                ? 'beklemede olan'
                : 'onaylanmış';
            return response()->json([
                'message' => "Bu tarih için zaten {$statusLabel} bir rezervasyonunuz var.",
                'existing_reservation' => $existingReservation,
            ], 422);
        }

        // Yeni yapı: schedule kullanılıyorsa
        if (!empty($validated['schedule_id'])) {
            return $this->createWithSchedule($request, $listing, $validated);
        }

        // Eski yapı: availability kullanılıyorsa (geriye uyumluluk)
        return $this->createWithAvailability($request, $listing, $validated);
    }

    /**
     * Yeni yapı ile rezervasyon oluştur (schedule)
     */
    private function createWithSchedule(Request $request, Listing $listing, array $validated): JsonResponse
    {
        $schedule = ListingSchedule::findOrFail($validated['schedule_id']);

        if ($schedule->listing_id !== $listing->id) {
            return response()->json([
                'message' => 'Tarih bu ilana ait değil.',
            ], 422);
        }

        if (!$schedule->hasCapacity($validated['guest_count'])) {
            return response()->json([
                'message' => 'Yeterli kontenjan bulunmuyor. Kalan: ' . $schedule->remaining_capacity,
            ], 422);
        }

        // Fiyat hesapla (schedule'da özel fiyat varsa onu kullan)
        $unitPrice = $schedule->price_override ?? $listing->price;
        $totalAmount = $listing->pricing_type->value === 'per_person'
            ? $unitPrice * $validated['guest_count']
            : $unitPrice;

        // Create reservation in transaction
        $reservation = DB::transaction(function () use ($validated, $schedule, $unitPrice, $totalAmount, $request) {
            // Book capacity
            $schedule->bookCapacity($validated['guest_count']);

            // Create reservation
            return Reservation::create([
                'user_id' => $request->user()->id,
                'source' => ReservationSource::APP,
                'listing_id' => $validated['listing_id'],
                'listing_schedule_id' => $validated['schedule_id'],
                'reservation_date' => $schedule->date,
                'guest_count' => $validated['guest_count'],
                'unit_price' => $unitPrice,
                'total_amount' => $totalAmount,
                'status' => ReservationStatus::PENDING,
                'customer_note' => $validated['customer_note'] ?? null,
            ]);
        });

        $reservation->load(['listing.coverImage', 'listing.owner', 'schedule']);

        $owner = $reservation->listing->owner;
        if ($owner->notifications_enabled) {
            $owner->notify(new ReservationCreated($reservation));

            try {
                broadcast(new UserNotificationsUpdated(
                    userId: $owner->id,
                    type: 'reservation',
                    notificationType: 'reservation_created',
                    title: 'Yeni Rezervasyon Talebi',
                    message: 'Yeni rezervasyon talebi: ' . $reservation->listing->title,
                    actionUrl: '/owner/reservations',
                ));
            } catch (\Throwable $e) {
                \Log::error('ReservationCreated broadcast hatası', ['error' => $e->getMessage()]);
            }
        }

        SendAdminNotification::dispatch('new_reservation', ['reservation_id' => $reservation->id]);

        return response()->json([
            'message' => 'Rezervasyon oluşturuldu',
            'reservation' => $reservation,
        ], 201);
    }

    /**
     * Eski yapı ile rezervasyon oluştur (availability) - geriye uyumluluk
     */
    private function createWithAvailability(Request $request, Listing $listing, array $validated): JsonResponse
    {
        $availability = ListingAvailability::findOrFail($validated['availability_id']);

        if ($availability->listing_id !== $listing->id) {
            return response()->json([
                'message' => 'Müsaitlik bu ilana ait değil.',
            ], 422);
        }

        if (!$availability->hasAvailableSlots($validated['guest_count'])) {
            return response()->json([
                'message' => 'Yeterli kontenjan bulunmuyor.',
            ], 422);
        }

        // Calculate total
        $unitPrice = $listing->price;
        $totalAmount = $listing->pricing_type->value === 'per_person'
            ? $unitPrice * $validated['guest_count']
            : $unitPrice;

        // Create reservation in transaction
        $reservation = DB::transaction(function () use ($validated, $availability, $unitPrice, $totalAmount, $request) {
            // Book slots
            $availability->bookSlots($validated['guest_count']);

            // Create reservation
            return Reservation::create([
                'user_id' => $request->user()->id,
                'source' => ReservationSource::APP,
                'listing_id' => $validated['listing_id'],
                'listing_availability_id' => $validated['availability_id'],
                'reservation_date' => $availability->date,
                'guest_count' => $validated['guest_count'],
                'unit_price' => $unitPrice,
                'total_amount' => $totalAmount,
                'status' => ReservationStatus::PENDING,
                'customer_note' => $validated['customer_note'] ?? null,
            ]);
        });

        $reservation->load(['listing.coverImage', 'listing.owner', 'availability']);

        $owner = $reservation->listing->owner;
        if ($owner->notifications_enabled) {
            $owner->notify(new ReservationCreated($reservation));

            try {
                broadcast(new UserNotificationsUpdated(
                    userId: $owner->id,
                    type: 'reservation',
                    notificationType: 'reservation_created',
                    title: 'Yeni Rezervasyon Talebi',
                    message: 'Yeni rezervasyon talebi: ' . $reservation->listing->title,
                    actionUrl: '/owner/reservations',
                ));
            } catch (\Throwable $e) {
                \Log::error('ReservationCreated broadcast hatası', ['error' => $e->getMessage()]);
            }
        }

        SendAdminNotification::dispatch('new_reservation', ['reservation_id' => $reservation->id]);

        return response()->json([
            'message' => 'Rezervasyon oluşturuldu',
            'reservation' => $reservation,
        ], 201);
    }

    /**
     * Cancel reservation
     */
    public function cancel(Reservation $reservation): JsonResponse
    {
        // Ensure user owns this reservation
        if ($reservation->user_id !== request()->user()->id) {
            return response()->json([
                'message' => 'Rezervasyon bulunamadı.',
            ], 404);
        }

        if (!$reservation->canBeCancelled()) {
            return response()->json([
                'message' => 'Bu rezervasyon iptal edilemez.',
            ], 422);
        }

        $oldStatus = $reservation->status->value ?? $reservation->status;
        $reservation->cancel();
        $reservation->load('listing.owner');

        $owner = $reservation->listing->owner;
        if ($owner->notifications_enabled) {
            $owner->notify(new ReservationCancelled($reservation));

            try {
                broadcast(new UserNotificationsUpdated(
                    userId: $owner->id,
                    type: 'reservation',
                    notificationType: 'reservation_cancelled',
                    title: 'Rezervasyon İptal Edildi',
                    message: 'Rezervasyon iptal edildi: ' . $reservation->listing->title,
                    actionUrl: '/owner/reservations',
                ));
            } catch (\Throwable $e) {
                \Log::error('ReservationCancelled broadcast hatası', ['error' => $e->getMessage()]);
            }
        }

        SendAdminNotification::dispatch('reservation_status', [
            'reservation_id' => $reservation->id,
            'old_status' => $oldStatus,
        ]);

        return response()->json([
            'message' => 'Rezervasyon iptal edildi',
            'reservation' => $reservation->fresh(),
        ]);
    }
}
