<?php

namespace App\Http\Controllers\Api\Owner;

use App\Enums\ListingStatus;
use App\Events\UserNotificationsUpdated;
use App\Http\Controllers\Controller;
use App\Jobs\SendAdminNotification;
use App\Jobs\SendPushNotification;
use App\Models\FavoriteListing;
use App\Models\Listing;
use App\Models\ListingAvailability;
use App\Models\ListingImage;
use App\Models\ListingSchedule;
use App\Models\ListingWaitlist;
use App\Notifications\ListingAvailableNotification;
use App\Notifications\NewScheduleAddedNotification;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Services\ImageService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class ListingController extends Controller
{
    /**
     * Get owner's listings
     */
    public function index(Request $request): JsonResponse
    {
        $query = $request->user()
            ->listings()
            ->with(['listingType', 'city.province', 'coverImage']);

        // Status filtresi
        if ($request->has('status') && $request->status) {
            $query->where('status', $request->status);
        }

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

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

    /**
     * Get single listing
     */
    public function show(Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $listing->load(['listingType', 'city.province', 'images', 'availabilities', 'amenityItems']);

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

    /**
     * Create new listing
     */
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'boat_id' => ['required', 'exists:boats,id'],
            'listing_type_id' => ['required', 'exists:listing_types,id'],
            'city_id' => ['required', 'exists:cities,id'],
            'title' => ['required', 'string', 'max:255'],
            'description' => ['required', 'string'],
            'pricing_type' => ['required', 'in:per_person,per_boat'],
            'price' => ['required', 'numeric', 'min:0'],
            'capacity' => ['required', 'integer', 'min:1'],
            'duration_hours' => ['required', 'integer', 'min:1'],
            'address' => ['nullable', 'string', 'max:500'],
            'latitude' => ['nullable', 'numeric', 'between:-90,90'],
            'longitude' => ['nullable', 'numeric', 'between:-180,180'],
            'amenities' => ['nullable', 'array'],
            'amenity_ids' => ['nullable', 'array'],
            'amenity_ids.*' => ['integer', 'exists:amenities,id'],
            'status' => ['nullable', 'in:draft,active'],
        ]);

        $boat = \App\Models\Boat::find($validated['boat_id']);
        if (!$boat || $boat->user_id !== $request->user()->id) {
            return response()->json(['message' => 'Bu tekne size ait değil.'], 403);
        }

        $amenityIds = $validated['amenity_ids'] ?? [];
        $syncAmenities = array_key_exists('amenity_ids', $validated);
        unset($validated['amenity_ids']);

        $validated['user_id'] = $request->user()->id;
        $validated['status'] = $validated['status'] ?? ListingStatus::DRAFT;

        $listing = Listing::create($validated);

        if ($syncAmenities) {
            $listing->amenityItems()->sync($amenityIds);
        }

        SendAdminNotification::dispatch('new_listing', ['listing_id' => $listing->id]);

        return response()->json([
            'message' => 'İlan oluşturuldu',
            'listing' => $listing->load(['listingType', 'city.province', 'amenityItems']),
        ], 201);
    }

    /**
     * Update listing
     */
    public function update(Request $request, Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $validated = $request->validate([
            'boat_id' => ['sometimes', 'exists:boats,id'],
            'listing_type_id' => ['sometimes', 'exists:listing_types,id'],
            'city_id' => ['sometimes', 'exists:cities,id'],
            'title' => ['sometimes', 'string', 'max:255'],
            'description' => ['sometimes', 'string'],
            'pricing_type' => ['sometimes', 'in:per_person,per_boat'],
            'price' => ['sometimes', 'numeric', 'min:0'],
            'capacity' => ['sometimes', 'integer', 'min:1'],
            'duration_hours' => ['sometimes', 'integer', 'min:1'],
            'address' => ['nullable', 'string', 'max:500'],
            'latitude' => ['nullable', 'numeric', 'between:-90,90'],
            'longitude' => ['nullable', 'numeric', 'between:-180,180'],
            'amenities' => ['nullable', 'array'],
            'amenity_ids' => ['nullable', 'array'],
            'amenity_ids.*' => ['integer', 'exists:amenities,id'],
            'status' => ['sometimes', 'in:draft,active,inactive'],
        ]);

        $amenityIds = $validated['amenity_ids'] ?? [];
        $syncAmenities = array_key_exists('amenity_ids', $validated);
        unset($validated['amenity_ids']);

        $listing->update($validated);

        if ($syncAmenities) {
            $listing->amenityItems()->sync($amenityIds);
        }

        return response()->json([
            'message' => 'İlan güncellendi',
            'listing' => $listing->fresh(['listingType', 'city.province', 'images', 'amenityItems']),
        ]);
    }

    /**
     * Delete listing
     */
    public function destroy(Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        // Check for pending/approved reservations
        $hasActiveReservations = $listing->reservations()
            ->whereIn('status', ['pending', 'approved'])
            ->exists();

        if ($hasActiveReservations) {
            return response()->json([
                'message' => 'Aktif rezervasyonları olan bir ilan silinemez.',
            ], 422);
        }

        // Delete images from storage
        foreach ($listing->images as $image) {
            Storage::disk('public')->delete($image->path);
        }

        $listing->delete();

        return response()->json([
            'message' => 'İlan silindi',
        ]);
    }

    /**
     * Upload images
     */
    public function uploadImages(Request $request, Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $request->validate([
            'images' => ['required', 'array', 'max:10'],
            'images.*' => ['required', 'image', 'max:5120'], // 5MB max
        ]);

        $uploadedImages = [];
        $currentMaxOrder = $listing->images()->max('sort_order') ?? -1;
        $imageService = app(ImageService::class);

        foreach ($request->file('images') as $index => $image) {
            $path = $imageService->compress(
                $image,
                'listings/' . $listing->id,
                ImageService::PRESET_LISTING,
            );

            $listingImage = ListingImage::create([
                'listing_id' => $listing->id,
                'path' => $path,
                'sort_order' => $currentMaxOrder + $index + 1,
                'is_cover' => $listing->images()->count() === 0 && $index === 0,
            ]);

            $uploadedImages[] = $listingImage;
        }

        return response()->json([
            'message' => 'Resimler yüklendi',
            'images' => $uploadedImages,
        ]);
    }

    /**
     * Delete image
     */
    public function deleteImage(Listing $listing, ListingImage $image): JsonResponse
    {
        $this->authorizeOwnership($listing);

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

        Storage::disk('public')->delete($image->path);
        
        $wasCover = $image->is_cover;
        $image->delete();

        // If deleted image was cover, set first image as cover
        if ($wasCover) {
            $firstImage = $listing->images()->orderBy('sort_order')->first();
            if ($firstImage) {
                $firstImage->update(['is_cover' => true]);
            }
        }

        return response()->json([
            'message' => 'Resim silindi',
        ]);
    }

    /**
     * Set cover image
     */
    public function setCoverImage(Listing $listing, ListingImage $image): JsonResponse
    {
        $this->authorizeOwnership($listing);

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

        // Remove cover from all images
        $listing->images()->update(['is_cover' => false]);

        // Set new cover
        $image->update(['is_cover' => true]);

        return response()->json([
            'message' => 'Kapak resmi güncellendi',
        ]);
    }

    /**
     * Get availabilities
     */
    public function availabilities(Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $availabilities = $listing->availabilities()
            ->orderBy('date')
            ->orderBy('start_time')
            ->get();

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

    /**
     * Create availability
     */
    public function storeAvailability(Request $request, Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $validated = $request->validate([
            'date' => ['required', 'date', 'after_or_equal:today'],
            'start_time' => ['required', 'date_format:H:i'],
            'end_time' => ['required', 'date_format:H:i', 'after:start_time'],
            'available_slots' => ['required', 'integer', 'min:1'],
        ]);

        // Check for overlapping availability
        $exists = $listing->availabilities()
            ->where('date', $validated['date'])
            ->where('start_time', $validated['start_time'])
            ->exists();

        if ($exists) {
            return response()->json([
                'message' => 'Bu tarih ve saat için zaten müsaitlik tanımlanmış.',
            ], 422);
        }

        $availability = $listing->availabilities()->create($validated);

        return response()->json([
            'message' => 'Müsaitlik eklendi',
            'availability' => $availability,
        ], 201);
    }

    /**
     * Update availability
     */
    public function updateAvailability(Request $request, ListingAvailability $availability): JsonResponse
    {
        $listing = $availability->listing;
        $this->authorizeOwnership($listing);

        $validated = $request->validate([
            'date' => ['sometimes', 'date', 'after_or_equal:today'],
            'start_time' => ['sometimes', 'date_format:H:i'],
            'end_time' => ['sometimes', 'date_format:H:i', 'after:start_time'],
            'available_slots' => ['sometimes', 'integer', 'min:1'],
            'is_available' => ['sometimes', 'boolean'],
        ]);

        // Ensure available_slots is not less than booked_slots
        if (isset($validated['available_slots']) && $validated['available_slots'] < $availability->booked_slots) {
            return response()->json([
                'message' => 'Müsait slot sayısı, rezerve edilmiş slot sayısından az olamaz.',
            ], 422);
        }

        $availability->update($validated);

        return response()->json([
            'message' => 'Müsaitlik güncellendi',
            'availability' => $availability->fresh(),
        ]);
    }

    /**
     * Delete availability
     */
    public function deleteAvailability(ListingAvailability $availability): JsonResponse
    {
        $listing = $availability->listing;
        $this->authorizeOwnership($listing);

        // Check for existing reservations
        if ($availability->booked_slots > 0) {
            return response()->json([
                'message' => 'Rezervasyonu olan müsaitlik silinemez.',
            ], 422);
        }

        $availability->delete();

        return response()->json([
            'message' => 'Müsaitlik silindi',
        ]);
    }

    // =====================================================
    // SCHEDULE METHODS (Yeni Tarih/Kapasite Yapısı)
    // =====================================================

    /**
     * Get listing schedules
     */
    public function schedules(Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $schedules = $listing->schedules()
            ->orderBy('date')
            ->orderBy('start_time')
            ->get();

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

    /**
     * Add schedules (toplu tarih ekleme)
     */
    public function storeSchedules(Request $request, Listing $listing): JsonResponse
    {
        $this->authorizeOwnership($listing);

        $validated = $request->validate([
            'schedules' => ['required', 'array', 'min:1'],
            'schedules.*.date' => ['required', 'date', 'after_or_equal:today'],
            'schedules.*.start_time' => ['required', 'date_format:H:i'],
            'schedules.*.end_time' => ['required', 'date_format:H:i', 'after:schedules.*.start_time'],
            'schedules.*.capacity' => ['required', 'integer', 'min:1'],
            'schedules.*.price_override' => ['nullable', 'numeric', 'min:0'],
        ]);

        $createdSchedules = [];
        $errors = [];

        DB::beginTransaction();
        try {
            foreach ($validated['schedules'] as $index => $scheduleData) {
                // Aynı tarih/saat için çakışma kontrolü
                $exists = $listing->schedules()
                    ->where('date', $scheduleData['date'])
                    ->where('start_time', $scheduleData['start_time'])
                    ->exists();

                if ($exists) {
                    $errors[] = "Tarih {$scheduleData['date']} saat {$scheduleData['start_time']} için zaten kayıt var.";
                    continue;
                }

                $schedule = $listing->schedules()->create([
                    'date' => $scheduleData['date'],
                    'start_time' => $scheduleData['start_time'],
                    'end_time' => $scheduleData['end_time'],
                    'capacity' => $scheduleData['capacity'],
                    'price_override' => $scheduleData['price_override'] ?? null,
                    'is_active' => true,
                ]);

                $createdSchedules[] = $schedule;
            }

            DB::commit();

            if (count($createdSchedules) > 0) {
                $this->notifyFavoriteUsers($listing, count($createdSchedules));
                $this->notifyWaitlistUsers($listing);
            }

            return response()->json([
                'message' => count($createdSchedules) . ' tarih eklendi',
                'schedules' => $createdSchedules,
                'errors' => $errors,
            ], 201);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'message' => 'Tarihler eklenirken hata oluştu.',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Update single schedule
     */
    public function updateSchedule(Request $request, ListingSchedule $schedule): JsonResponse
    {
        $listing = $schedule->listing;
        $this->authorizeOwnership($listing);

        $validated = $request->validate([
            'date' => ['sometimes', 'date', 'after_or_equal:today'],
            'start_time' => ['sometimes', 'date_format:H:i'],
            'end_time' => ['sometimes', 'date_format:H:i'],
            'capacity' => ['sometimes', 'integer', 'min:1'],
            'price_override' => ['nullable', 'numeric', 'min:0'],
            'is_active' => ['sometimes', 'boolean'],
        ]);

        // Kapasite, rezerve edilmiş sayıdan az olamaz
        if (isset($validated['capacity']) && $validated['capacity'] < $schedule->booked_count) {
            return response()->json([
                'message' => 'Kapasite, mevcut rezervasyon sayısından (' . $schedule->booked_count . ') az olamaz.',
            ], 422);
        }

        // Tarih/saat değişiyorsa çakışma kontrolü
        $newDate = $validated['date'] ?? $schedule->date->format('Y-m-d');
        $newStartTime = $validated['start_time'] ?? $schedule->start_time->format('H:i');
        
        if ($newDate !== $schedule->date->format('Y-m-d') || $newStartTime !== $schedule->start_time->format('H:i')) {
            $exists = $listing->schedules()
                ->where('id', '!=', $schedule->id)
                ->where('date', $newDate)
                ->where('start_time', $newStartTime)
                ->exists();

            if ($exists) {
                return response()->json([
                    'message' => 'Bu tarih ve saat için zaten kayıt var.',
                ], 422);
            }
        }

        $schedule->update($validated);

        return response()->json([
            'message' => 'Tarih güncellendi',
            'schedule' => $schedule->fresh(),
        ]);
    }

    /**
     * Delete schedule
     */
    public function deleteSchedule(ListingSchedule $schedule): JsonResponse
    {
        $listing = $schedule->listing;
        $this->authorizeOwnership($listing);

        // Rezervasyonu olan tarih silinemez
        if ($schedule->booked_count > 0) {
            return response()->json([
                'message' => 'Rezervasyonu olan tarih silinemez. Önce rezervasyonları iptal edin.',
            ], 422);
        }

        $schedule->delete();

        return response()->json([
            'message' => 'Tarih silindi',
        ]);
    }

    /**
     * Authorize ownership of listing
     */
    private function authorizeOwnership(Listing $listing): void
    {
        if ($listing->user_id !== request()->user()->id && !request()->user()->isAdmin()) {
            abort(403, 'Bu işlem için yetkiniz yok.');
        }
    }

    /**
     * Bekleme listesindeki kullanıcılara boş yer bildirimi gönder
     */
    private function notifyWaitlistUsers(Listing $listing): void
    {
        $waitlistEntries = ListingWaitlist::where('listing_id', $listing->id)->with('user')->get();

        if ($waitlistEntries->isEmpty()) {
            return;
        }

        foreach ($waitlistEntries as $entry) {
            $user = $entry->user;
            if (!$user || !($user->notifications_enabled ?? true)) {
                continue;
            }

            $user->notify(new ListingAvailableNotification($listing));

            try {
                broadcast(new UserNotificationsUpdated(
                    userId: $user->id,
                    type: 'listing_available',
                    notificationType: 'listing_available',
                    title: 'Boş Yer Açıldı!',
                    message: $listing->title . ' ilanında yeni tarih eklendi.',
                    actionUrl: '/listings/' . $listing->id,
                ));
            } catch (\Throwable $e) {
                \Log::warning('Waitlist broadcast hatası: ' . $e->getMessage());
            }

            SendPushNotification::dispatch(
                $user,
                'Boş Yer Açıldı!',
                $listing->title . ' ilanında yeni tarih eklendi.',
                [
                    'type' => 'listing_available',
                    'listing_id' => $listing->id,
                ]
            );
        }

        ListingWaitlist::where('listing_id', $listing->id)->delete();
    }

    /**
     * Favoriye almış kullanıcılara yeni tarih bildirimi gönder
     */
    private function notifyFavoriteUsers(Listing $listing, int $scheduleCount): void
    {
        $favoriteUsers = FavoriteListing::where('listing_id', $listing->id)
            ->with('user')
            ->get()
            ->pluck('user')
            ->filter();

        \Log::info('Favori bildirimi gönderiliyor', [
            'listing_id' => $listing->id,
            'user_count' => $favoriteUsers->count(),
        ]);

        foreach ($favoriteUsers as $user) {
            if (!$user || !($user->notifications_enabled ?? true)) {
                continue;
            }

            try {
                $user->notify(new NewScheduleAddedNotification($listing, $scheduleCount));
            } catch (\Throwable $e) {
                \Log::error('Favori bildirim database hatası', [
                    'user_id' => $user->id,
                    'listing_id' => $listing->id,
                    'error' => $e->getMessage(),
                ]);
            }

            try {
                broadcast(new UserNotificationsUpdated(
                    userId: $user->id,
                    type: 'favorite_listing',
                    notificationType: 'new_schedule_added',
                    title: 'Favori İlanınızda Yeni Tarih!',
                    message: $listing->title . ' ilanına yeni tarih eklendi.',
                    actionUrl: '/listings/' . $listing->id,
                ));
            } catch (\Throwable $e) {
                \Log::error('Favori bildirim broadcast hatası', [
                    'user_id' => $user->id,
                    'listing_id' => $listing->id,
                    'error' => $e->getMessage(),
                ]);
            }

            SendPushNotification::dispatch(
                $user,
                'Favori İlanınızda Yeni Tarih!',
                $listing->title . ' ilanına yeni tarih eklendi.',
                [
                    'type' => 'new_schedule_added',
                    'listing_id' => $listing->id,
                ]
            );
        }
    }
}
