<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Listing;
use App\Models\ListingSchedule;
use App\Models\ListingType;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ListingController extends Controller
{
    /**
     * Get all active listings with filters
     */
    public function index(Request $request): JsonResponse
    {
        $query = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
            ->active();

        // Filter by listing type
        if ($request->has('type_id')) {
            $query->ofType($request->type_id);
        }

        // Filter by city
        if ($request->has('city_id')) {
            $query->inCity($request->city_id);
        }

        // Filter by province (get all cities in province)
        if ($request->has('province_id')) {
            $query->whereHas('city', function ($q) use ($request) {
                $q->where('province_id', $request->province_id);
            });
        }

        // Price range filter
        if ($request->has('min_price') || $request->has('max_price')) {
            $query->priceRange($request->min_price, $request->max_price);
        }

        // Capacity filter
        if ($request->has('min_capacity')) {
            $query->where('capacity', '>=', $request->min_capacity);
        }

        // Boat type filter
        if ($request->filled('boat_type')) {
            $query->whereHas('boat', fn ($q) => $q->where('boat_type', $request->boat_type));
        }

        // Boat build year filter
        if ($request->filled('min_build_year')) {
            $query->whereHas('boat', fn ($q) => $q->where('build_year', '>=', (int) $request->min_build_year));
        }
        if ($request->filled('max_build_year')) {
            $query->whereHas('boat', fn ($q) => $q->where('build_year', '<=', (int) $request->max_build_year));
        }

        // Boat length filter (meters)
        if ($request->filled('min_length')) {
            $query->whereHas('boat', fn ($q) => $q->where('length_meters', '>=', (float) $request->min_length));
        }
        if ($request->filled('max_length')) {
            $query->whereHas('boat', fn ($q) => $q->where('length_meters', '<=', (float) $request->max_length));
        }

        // Search by title or description
        if ($request->has('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('title', 'like', "%{$search}%")
                    ->orWhere('description', 'like', "%{$search}%");
            });
        }

        // Sort
        $sortBy = $request->get('sort_by', 'created_at');
        $sortOrder = $request->get('sort_order', 'desc');

        if (in_array($sortBy, ['fish_score', 'tour_score'])) {
            $scoreDate = $request->get('date', now()->format('Y-m-d'));
            $perPage = min($request->get('per_page', 15), 50);
            $listings = $query->paginate($perPage);

            $seaService = app(\App\Services\SeaConditions\SeaConditionsService::class);
            $listings->getCollection()->transform(function ($listing) use ($seaService, $scoreDate) {
                $lat = $listing->latitude ?? $listing->city?->latitude;
                $lng = $listing->longitude ?? $listing->city?->longitude;
                if ($lat && $lng) {
                    $score = $seaService->getListingScore($lat, $lng, $scoreDate);
                    $listing->setAttribute('sea_score', $score);
                }
                return $listing;
            });

            $mode = $sortBy === 'fish_score' ? 'fish_score' : 'tour_score';
            $sorted = $listings->getCollection()->sortByDesc(fn ($l) => $l->sea_score[$mode] ?? 0)->values();
            $listings->setCollection($sorted);

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

        if (in_array($sortBy, ['created_at', 'price', 'view_count'])) {
            $query->orderBy($sortBy, $sortOrder);
        }

        // Pagination
        $perPage = min($request->get('per_page', 15), 50);
        $listings = $query->paginate($perPage);

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

    /**
     * Get listing details
     */
    public function show(Listing $listing): JsonResponse
    {
        if ($listing->status->value !== 'active') {
            return response()->json([
                'message' => 'İlan bulunamadı.',
            ], 404);
        }

        // Increment view count
        $listing->incrementViewCount();

        $listing->load([
            'listingType',
            'city.province',
            'coverImage',
            'images',
            'boat',
            'amenityItems',
            'owner:id,name,avatar,bio,phone',
            'availabilities' => function ($query) {
                $query->available()->future()->orderBy('date');
            },
            'schedules' => function ($query) {
                $query->available()->orderBy('date')->orderBy('start_time');
            }
        ]);

        $captainId = $listing->user_id;
        $reviewCount = \App\Models\CaptainReview::where('captain_id', $captainId)->count();
        $averageRating = $reviewCount > 0
            ? round(\App\Models\CaptainReview::where('captain_id', $captainId)->avg('rating'), 1)
            : 0;

        return response()->json([
            'listing' => $listing,
            'captain_review_stats' => [
                'average_rating' => $averageRating,
                'total_count' => $reviewCount,
            ],
        ]);
    }

    /**
     * OG meta verileri (sosyal medya paylaşımları için)
     */
    public function meta(Listing $listing): JsonResponse
    {
        $listing->load(['coverImage', 'listingType', 'city.province', 'owner:id,name']);

        $coverUrl = $listing->coverImage
            ? asset('storage/' . $listing->coverImage->path)
            : null;

        return response()->json([
            'title' => $listing->title,
            'description' => mb_substr(strip_tags($listing->description), 0, 200),
            'image' => $coverUrl,
            'price' => $listing->price,
            'pricing_type' => $listing->pricing_type,
            'capacity' => $listing->capacity,
            'location' => $listing->city
                ? ($listing->city->name . ', ' . ($listing->city->province->name ?? ''))
                : null,
            'category' => $listing->listingType?->name,
            'captain' => $listing->owner?->name,
        ]);
    }

    /**
     * Get listing availabilities (eski yapı - geriye uyumluluk)
     */
    public function availabilities(Listing $listing, Request $request): JsonResponse
    {
        $query = $listing->availabilities()
            ->available()
            ->future();

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

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

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

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

    /**
     * Get listing schedules (yeni yapı - tarih/kapasite bazlı)
     */
    public function schedules(Listing $listing, Request $request): JsonResponse
    {
        if ($listing->status->value !== 'active') {
            return response()->json([
                'message' => 'İlan bulunamadı.',
            ], 404);
        }

        $query = $listing->schedules()
            ->available();

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

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

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

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

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

    /**
     * Get specific schedule details
     */
    public function scheduleDetail(Listing $listing, string $date): JsonResponse
    {
        if ($listing->status->value !== 'active') {
            return response()->json([
                'message' => 'İlan bulunamadı.',
            ], 404);
        }

        $schedules = $listing->schedules()
            ->where('date', $date)
            ->where('is_active', true)
            ->orderBy('start_time')
            ->get();

        if ($schedules->isEmpty()) {
            return response()->json([
                'message' => 'Bu tarih için müsait seans bulunamadı.',
            ], 404);
        }

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

    /**
     * Get all listing types
     */
    public function types(): JsonResponse
    {
        $types = ListingType::active()->get();

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

    /**
     * Get featured listings for homepage (vitrin ilanları)
     */
    public function featured(): JsonResponse
    {
        // Önce ücretli vitrin ilanlarını getir
        $featuredListings = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
            ->active()
            ->featured()
            ->limit(15)
            ->get();

        // Eğer vitrin ilanı yoksa veya 15'ten azsa, popüler ilanlarla doldur (fallback)
        $remainingCount = 15 - $featuredListings->count();
        $fallbackListings = collect();
        
        if ($remainingCount > 0) {
            $excludeIds = $featuredListings->pluck('id')->toArray();
            
            $fallbackListings = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
                ->active()
                ->whereNotIn('id', $excludeIds)
                ->orderBy('view_count', 'desc')
                ->limit($remainingCount)
                ->get();
        }

        $allListings = $featuredListings->concat($fallbackListings);

        return response()->json([
            'listings' => $allListings,
            'featured_count' => $featuredListings->count(),
            'total' => $allListings->count(),
        ]);
    }

    /**
     * Get popular destinations based on reservations
     */
    public function popularDestinations(): JsonResponse
    {
        $destinations = \DB::table('reservations')
            ->join('listings', 'reservations.listing_id', '=', 'listings.id')
            ->join('cities', 'listings.city_id', '=', 'cities.id')
            ->join('provinces', 'cities.province_id', '=', 'provinces.id')
            ->leftJoin('listing_images', function ($join) {
                $join->on('listings.id', '=', 'listing_images.listing_id')
                    ->where('listing_images.is_cover', '=', true);
            })
            ->whereIn('reservations.status', ['approved', 'completed'])
            ->whereNull('listings.deleted_at')
            ->select(
                'cities.id as city_id',
                'cities.name as city_name',
                'provinces.name as province_name',
                \DB::raw('COUNT(reservations.id) as reservation_count'),
                \DB::raw('MAX(listing_images.path) as image_path')
            )
            ->groupBy('cities.id', 'cities.name', 'provinces.name')
            ->orderByDesc('reservation_count')
            ->limit(8)
            ->get()
            ->map(function ($item) {
                return [
                    'city_id' => $item->city_id,
                    'city_name' => $item->city_name,
                    'province_name' => $item->province_name,
                    'reservation_count' => $item->reservation_count,
                    'image_url' => $item->image_path 
                        ? url(\Illuminate\Support\Facades\Storage::url($item->image_path))
                        : null,
                ];
            });

        // Eğer rezervasyon bazlı veri yoksa, en çok görüntülenen şehirleri getir
        if ($destinations->isEmpty()) {
            $destinations = \DB::table('listings')
                ->join('cities', 'listings.city_id', '=', 'cities.id')
                ->join('provinces', 'cities.province_id', '=', 'provinces.id')
                ->leftJoin('listing_images', function ($join) {
                    $join->on('listings.id', '=', 'listing_images.listing_id')
                        ->where('listing_images.is_cover', '=', true);
                })
                ->where('listings.status', 'active')
                ->whereNull('listings.deleted_at')
                ->select(
                    'cities.id as city_id',
                    'cities.name as city_name',
                    'provinces.name as province_name',
                    \DB::raw('COUNT(listings.id) as listing_count'),
                    \DB::raw('SUM(listings.view_count) as total_views'),
                    \DB::raw('MAX(listing_images.path) as image_path')
                )
                ->groupBy('cities.id', 'cities.name', 'provinces.name')
                ->orderByDesc('total_views')
                ->limit(8)
                ->get()
                ->map(function ($item) {
                    return [
                        'city_id' => $item->city_id,
                        'city_name' => $item->city_name,
                        'province_name' => $item->province_name,
                        'listing_count' => $item->listing_count,
                        'image_url' => $item->image_path 
                            ? url(\Illuminate\Support\Facades\Storage::url($item->image_path))
                            : null,
                    ];
                });
        }

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

    /**
     * Get suggested listings based on user's recent views or location
     */
    public function suggestions(Request $request): JsonResponse
    {
        $cityIds = $request->get('city_ids', []);
        if (is_string($cityIds)) {
            $cityIds = explode(',', $cityIds);
        }

        $excludeIds = $request->get('exclude_ids', []);
        if (is_string($excludeIds)) {
            $excludeIds = explode(',', $excludeIds);
        }
        
        $query = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
            ->active();

        // Eğer şehir ID'leri verilmişse, o şehirlerden öner
        if (!empty($cityIds)) {
            $query->whereIn('city_id', $cityIds);
        }

        // Dışarıda bırakılacak ilanları çıkar
        if (!empty($excludeIds)) {
            $query->whereNotIn('id', $excludeIds);
        }

        $listings = $query->orderBy('view_count', 'desc')
            ->limit(5)
            ->get();

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

    /**
     * Yakındaki ilanlar - konum bazlı, adil sıralama ile
     */
    public function nearby(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'radius' => 'nullable|numeric|min:1|max:200',
        ]);

        $lat = (float) $request->latitude;
        $lng = (float) $request->longitude;
        $radius = (float) $request->get('radius', 50);

        $dist = Listing::haversineExpression($lat, $lng);

        $listings = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
            ->active()
            ->nearby($lat, $lng, $radius)
            ->orderByRaw("(
                (1 - LEAST({$dist} / ?, 1)) * 0.4
                + (1 - LEAST(EXTRACT(DAY FROM NOW() - listings.created_at) / 90, 1)) * 0.2
                + (listings.view_count / (SELECT MAX(view_count) FROM listings WHERE status = 'active' AND deleted_at IS NULL)) * 0.2
                + RANDOM() * 0.2
            ) DESC", [$radius])
            ->limit(10)
            ->get();

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

    /**
     * Yarın müsait olan ilanlar - konum bazlı
     */
    public function availableTomorrow(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'radius' => 'nullable|numeric|min:1|max:200',
        ]);

        $lat = (float) $request->latitude;
        $lng = (float) $request->longitude;
        $radius = (float) $request->get('radius', 100);
        $tomorrow = now()->addDay()->toDateString();

        $listingIds = ListingSchedule::where('date', $tomorrow)
            ->where('is_active', true)
            ->whereColumn('booked_count', '<', 'capacity')
            ->pluck('listing_id')
            ->unique()
            ->toArray();

        if (empty($listingIds)) {
            return response()->json(['listings' => []]);
        }

        $listings = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
            ->active()
            ->whereIn('listings.id', $listingIds)
            ->nearby($lat, $lng, $radius)
            ->orderBy('distance_km')
            ->limit(10)
            ->get();

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

    /**
     * En çok tercih edilenler - konum bazlı popülerlik
     */
    public function mostPopular(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'radius' => 'nullable|numeric|min:1|max:200',
        ]);

        $lat = (float) $request->latitude;
        $lng = (float) $request->longitude;
        $radius = (float) $request->get('radius', 100);

        $dist = Listing::haversineExpression($lat, $lng);

        $listings = Listing::with(['listingType', 'city.province', 'coverImage', 'owner:id,name,avatar'])
            ->active()
            ->nearby($lat, $lng, $radius)
            ->addSelect(DB::raw("(SELECT COUNT(*) FROM reservations WHERE reservations.listing_id = listings.id AND reservations.status IN ('approved', 'completed')) as reservation_count"))
            ->orderByRaw("(
                (SELECT COUNT(*) FROM reservations WHERE reservations.listing_id = listings.id AND reservations.status IN ('approved', 'completed')) * 0.35
                + listings.view_count * 0.001 * 0.25
                + RANDOM() * 0.2
                + (1 - LEAST({$dist} / ?, 1)) * 0.2
            ) DESC", [$radius])
            ->limit(10)
            ->get();

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