<?php

namespace App\Http\Controllers;

use App\Models\PropertyPhoto;
use App\Models\PropertyFact;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Intervention\Image\Facades\Image;

class bulutController extends Controller
{
    const API_HOST = 'booking-com15.p.rapidapi.com';
    const API_BASE = 'https://booking-com15.p.rapidapi.com';

    private function client()
    {
        return new Client(array(
            'timeout' => 30,
            'headers' => array(
                'x-rapidapi-host' => env('BULUT_RAPIDAPI_HOST', self::API_HOST),
                'x-rapidapi-key'  => env('BULUT_RAPIDAPI_KEY'),
                'Content-Type'    => 'application/json',
            ),
        ));
    }


    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 1: Otel adına göre ara → hotel_id bul
    // GET /bulut/search?name=Grand+Yavuz+Hotel
    // ─────────────────────────────────────────────────────────────────────────────
    public function search(Request $request)
    {
        $name = $request->query('name', '');

        if (!$name) {
            return response()->json(array('status' => false, 'message' => 'name parametresi gerekli'), 422);
        }

        try {
            $response = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/searchDestination',
                array('query' => array('query' => $name))
            );

            $data = json_decode($response->getBody()->getContents(), true);

            return response()->json(array('status' => true, 'data' => $data));
        } catch (Exception $e) {
            Log::error('Bulut.search error: ' . $e->getMessage());
            return response()->json(array('status' => false, 'message' => $e->getMessage()), 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 2: Otel detayları
    // GET /bulut/hotel-data?hotel_id=89675&checkin=2026-06-01&checkout=2026-06-02
    // ─────────────────────────────────────────────────────────────────────────────
    public function hotelData(Request $request)
    {
        $hotelId  = $request->query('hotel_id');
        $checkin  = $request->query('checkin',  date('Y-m-d', strtotime('+30 days')));
        $checkout = $request->query('checkout', date('Y-m-d', strtotime('+31 days')));

        if (!$hotelId) {
            return response()->json(array('status' => false, 'message' => 'hotel_id gerekli'), 422);
        }

        try {
            $response = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/getHotelDetails',
                array('query' => array(
                    'hotel_id'         => $hotelId,
                    'arrival_date'     => $checkin,
                    'departure_date'   => $checkout,
                    'adults'           => 1,
                    'room_qty'         => 1,
                    'languagecode'     => 'en-us',
                    'currency_code'    => 'USD',
                    'units'            => 'metric',
                    'temperature_unit' => 'c',
                ))
            );

            $data = json_decode($response->getBody()->getContents(), true);
            return response()->json(array('status' => true, 'data' => $data));
        } catch (Exception $e) {
            Log::error('Bulut.hotelData error: ' . $e->getMessage());
            return response()->json(array('status' => false, 'message' => $e->getMessage()), 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 3: Otel fotoğraflarını indir → property_photo tablosuna kaydet
    // GET /bulut/hotel-photos?hotel_id=89675&property_id=1
    // ─────────────────────────────────────────────────────────────────────────────
    public function hotelPhotos(Request $request)
    {
        $hotelId    = $request->query('hotel_id');
        $propertyId = $request->query('property_id', 1);
        $limit      = (int) $request->query('limit', 20);

        if (!$hotelId) {
            return response()->json(array('status' => false, 'message' => 'hotel_id gerekli'), 422);
        }

        try {
            $response = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/getHotelPhotos',
                array('query' => array(
                    'hotel_id'    => $hotelId,
                    'page_number' => 1,
                ))
            );

            $data = json_decode($response->getBody()->getContents(), true);

            $savedPhotos = $this->processAndSavePhotos($data, $hotelId, $propertyId, $limit);

            return response()->json(array(
                'status'       => true,
                'hotel_id'     => $hotelId,
                'property_id'  => $propertyId,
                'photos_saved' => $savedPhotos,
            ));
        } catch (Exception $e) {
            Log::error('Bulut.hotelPhotos error: ' . $e->getMessage());
            return response()->json(array('status' => false, 'message' => $e->getMessage()), 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // TAM PIPELINE: otel adı gönder → ara → detay + fotoğrafları kaydet
    // GET /bulut/test-api?name=Grand+Yavuz+Hotel&property_id=1&limit=5
    // ─────────────────────────────────────────────────────────────────────────────
    public function testApi(Request $request)
    {
        $name       = $request->query('name', '');
        $propertyId = $request->query('property_id', 1);
        $checkin    = $request->query('checkin',  date('Y-m-d', strtotime('+30 days')));
        $checkout   = $request->query('checkout', date('Y-m-d', strtotime('+31 days')));
        $limit      = (int) $request->query('limit', 5);

        if (!$name) {
            return response()->json(array('status' => false, 'message' => 'name parametresi gerekli'), 422);
        }

        try {
            // ── 1. Ara ───────────────────────────────────────────────────────────
            $searchResponse = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/searchDestination',
                array('query' => array('query' => $name))
            );
            $searchData = json_decode($searchResponse->getBody()->getContents(), true);

            if (empty($searchData['data'])) {
                return response()->json(array(
                    'status'  => false,
                    'message' => 'Otel bulunamadı',
                    'raw'     => $searchData
                ), 404);
            }

            // Önce dest_type=hotel olanı bul, yoksa ilk sonucu al
            $hotelResult = null;
            foreach ($searchData['data'] as $item) {
                if (isset($item['dest_type']) && $item['dest_type'] === 'hotel') {
                    $hotelResult = $item;
                    break;
                }
            }
            if (!$hotelResult) {
                $hotelResult = $searchData['data'][0];
            }

            $hotelId   = isset($hotelResult['dest_id']) ? $hotelResult['dest_id'] : null;
            $hotelName = isset($hotelResult['label'])   ? $hotelResult['label']   : $name;

            if (!$hotelId) {
                return response()->json(array(
                    'status'        => false,
                    'message'       => 'hotel_id bulunamadı',
                    'search_result' => $hotelResult,
                ), 404);
            }

            // ── 2. Otel detayı ───────────────────────────────────────────────────
            $detailResponse = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/getHotelDetails',
                array('query' => array(
                    'hotel_id'         => $hotelId,
                    'arrival_date'     => $checkin,
                    'departure_date'   => $checkout,
                    'adults'           => 1,
                    'room_qty'         => 1,
                    'languagecode'     => 'en-us',
                    'currency_code'    => 'USD',
                    'units'            => 'metric',
                    'temperature_unit' => 'c',
                ))
            );
            $detailData = json_decode($detailResponse->getBody()->getContents(), true);

            // ── 3. Fotoğrafları çek ve kaydet ────────────────────────────────────
            $photoResponse = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/getHotelPhotos',
                array('query' => array(
                    'hotel_id'    => $hotelId,
                    'page_number' => 1,
                ))
            );
            $photoData   = json_decode($photoResponse->getBody()->getContents(), true);
            $savedPhotos = $this->processAndSavePhotos($photoData, $hotelId, $propertyId, $limit);

            // ── 4. Facility matching ──────────────────────────────────────────────
            $detail          = isset($detailData['data']) ? $detailData['data'] : $detailData;
            $facilityResult  = $this->matchAndLogFacilities($detail, $hotelId, $propertyId);

            return response()->json(array(
                'status'           => true,
                'hotel_id'         => $hotelId,
                'hotel_name'       => $hotelName,
                'hotel_details'    => $detail,
                'photos_saved'     => $savedPhotos,
                'facility_matching' => $facilityResult,
            ));
        } catch (Exception $e) {
            Log::error('Bulut.testApi error: ' . $e->getMessage());
            return response()->json(array('status' => false, 'message' => $e->getMessage()), 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Private: API'den gelen foto listesinden URL çıkar, indir, boyutlandır, DB'ye kaydet
    // ─────────────────────────────────────────────────────────────────────────────
    private function processAndSavePhotos(array $responseData, $hotelId, $propertyId, $limit = 20)
    {
        $photoUrls = $this->extractPhotoUrls($responseData);

        if (empty($photoUrls)) {
            return array(
                'count'   => 0,
                'message' => 'API yanıtında fotoğraf URL bulunamadı',
                'raw_keys' => array_keys($responseData),
            );
        }

        $uploadRoot = rtrim(Config::get('app.fileSystemDriver'), '/');
        $urlPath    = '/property-photos/' . $propertyId . '/';
        $filePath   = $uploadRoot . $urlPath;

        if (!File::exists($filePath)) {
            File::makeDirectory($filePath, 0777, true);
        }

        // Bu property için zaten default foto var mı?
        $hasDefault = PropertyPhoto::where('property_id', $propertyId)
            ->where('status', 1)
            ->where('is_default', 1)
            ->exists();

        $saved       = array();
        $isFirstPhoto = true;
        $total        = min(count($photoUrls), $limit);

        for ($i = 0; $i < $total; $i++) {
            $photoUrl = $photoUrls[$i];

            try {
                $fileName = time() . '_bk' . $hotelId . '_' . $i;
                $fileExt  = 'jpg';
                $tempPath = sys_get_temp_dir() . '/' . $fileName . '_orig.jpg';

                // ── İndir ─────────────────────────────────────────────────────────
                $this->downloadRawImage($photoUrl, $tempPath);

                // ── Intervention Image ile işle ───────────────────────────────────
                $image       = Image::make($tempPath);
                $imageWidth  = $image->width();
                $imageHeight = $image->height();
                $fileSize    = (int) ceil(filesize($tempPath) / 1024);
                $quality     = 80;

                // Orijinal (2000px üzeriyse küçült)
                if ($imageHeight > 2000 || $imageWidth > 2000) {
                    if ($imageHeight > $imageWidth) {
                        $r = $imageHeight / 2000;
                        $image->fit((int)($imageWidth / $r), 2000);
                    } else {
                        $r = $imageWidth / 2000;
                        $image->fit(2000, (int)($imageHeight / $r));
                    }
                }
                $image->encode($fileExt, $quality)->orientate()->save($filePath . $fileName . '.' . $fileExt);

                // _medium (max 1600x768)
                $mediumImage = Image::make($tempPath);
                $ratio       = $imageHeight > 0 ? ($imageHeight / 768) : 1;
                $resizeWidth = (int)($imageWidth / max($ratio, 1));
                if ($resizeWidth > 1599) {
                    $mediumImage->fit(1600, 768);
                } else {
                    $mediumImage->fit(max($resizeWidth, 1), 768);
                }
                $mediumImage->encode($fileExt, $quality)->orientate()->save($filePath . $fileName . '_medium.' . $fileExt);

                // _thumbnail (300x300)
                Image::make($tempPath)
                    ->fit(300, 300)
                    ->encode($fileExt, $quality)
                    ->orientate()
                    ->save($filePath . $fileName . '_thumbnail.' . $fileExt);

                // Temp dosyayı sil
                if (File::exists($tempPath)) {
                    File::delete($tempPath);
                }

                $isCompatible = ($imageWidth >= 1150 && $imageHeight >= 600) ? 1 : 0;
                $isDefault    = (!$hasDefault && $isFirstPhoto) ? 1 : 0;
                $isFirstPhoto = false;

                // ── DB'ye kaydet ──────────────────────────────────────────────────
                $photoRecord = PropertyPhoto::create(array(
                    'property_id'                     => $propertyId,
                    'property_photo_category_id'      => 1,
                    'photo_path'                      => $urlPath,
                    'photo_name'                      => $fileName,
                    'file_size'                       => $fileSize,
                    'file_ext'                        => $fileExt,
                    'photo_resolution'                => $imageWidth . 'x' . $imageHeight,
                    'is_default'                      => $isDefault,
                    'is_compatible_with_myweb_slider' => $isCompatible,
                    'photo_order'                     => 0,
                    'photo_rank'                      => 0,
                    'is_temp'                         => 1,
                    'status'                          => 1,
                    'created_by'                      => 1,
                    'updated_by'                      => 1,
                    'created_at'                      => time(),
                    'updated_at'                      => time(),
                ));

                $saved[] = array(
                    'db_id'      => $photoRecord->id,
                    'file_name'  => $fileName . '.' . $fileExt,
                    'resolution' => $imageWidth . 'x' . $imageHeight,
                    'source_url' => $photoUrl,
                );
            } catch (Exception $e) {
                Log::error('Bulut.photo.save [' . $i . ']: ' . $e->getMessage() . ' | ' . $photoUrl);
                $saved[] = array('error' => $e->getMessage(), 'source_url' => $photoUrl);
            }
        }

        return array(
            'saved_count'   => count(array_filter($saved, function ($s) {
                return !isset($s['error']);
            })),
            'total_in_api'  => count($photoUrls),
            'limit_applied' => $total,
            'photos'        => $saved,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // booking-com15 getHotelPhotos yanıtından URL listesi çıkar
    // ─────────────────────────────────────────────────────────────────────────────
    private function extractPhotoUrls(array $data)
    {
        $urls = array();

        // Format 1: data[] dizisi – her elemanın url_original / url_max / url alanı
        if (isset($data['data']) && is_array($data['data']) && !empty($data['data'])) {
            foreach ($data['data'] as $item) {
                if (!is_array($item)) {
                    continue;
                }
                if (!empty($item['url_original'])) {
                    $urls[] = $item['url_original'];
                } elseif (!empty($item['url_max'])) {
                    $urls[] = $item['url_max'];
                } elseif (!empty($item['url'])) {
                    $urls[] = $item['url'];
                } elseif (!empty($item['photo']['url_original'])) {
                    $urls[] = $item['photo']['url_original'];
                }
            }
        }

        // Format 2: data.photos[]
        if (empty($urls) && isset($data['data']['photos']) && is_array($data['data']['photos'])) {
            foreach ($data['data']['photos'] as $item) {
                if (!empty($item['url_original'])) {
                    $urls[] = $item['url_original'];
                } elseif (!empty($item['url'])) {
                    $urls[] = $item['url'];
                }
            }
        }

        // Format 3: photos[] direkt root'ta
        if (empty($urls) && isset($data['photos']) && is_array($data['photos'])) {
            foreach ($data['photos'] as $item) {
                if (!empty($item['url_original'])) {
                    $urls[] = $item['url_original'];
                } elseif (!empty($item['url'])) {
                    $urls[] = $item['url'];
                }
            }
        }

        return $urls;
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Görseli disk'e indir (GuzzleHttp sink kullan)
    // ─────────────────────────────────────────────────────────────────────────────
    private function downloadRawImage($url, $savePath)
    {
        $client = new Client(array(
            'timeout' => 30,
            'verify'  => false,
            'headers' => array('User-Agent' => 'Mozilla/5.0'),
        ));

        $response = $client->get($url, array('sink' => $savePath));

        if ($response->getStatusCode() !== 200) {
            throw new Exception('Image download failed HTTP ' . $response->getStatusCode() . ' | ' . $url);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Public: GET /bulut/match-facilities?hotel_id=89675&property_id=1
    // ─────────────────────────────────────────────────────────────────────────────
    public function matchFacilities(Request $request)
    {
        $hotelId    = $request->query('hotel_id', '');
        $propertyId = $request->query('property_id', 1);

        if (!$hotelId) {
            return response()->json(array('status' => false, 'message' => 'hotel_id gerekli'), 422);
        }

        try {
            $response = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/getHotelFacilities',
                array('query' => array('hotel_id' => $hotelId))
            );

            $data   = json_decode($response->getBody()->getContents(), true);
            $result = $this->matchAndLogFacilities(
                isset($data['data']) ? $data['data'] : array(),
                $hotelId,
                $propertyId
            );

            return response()->json(array(
                'status'   => true,
                'hotel_id' => $hotelId,
                'result'   => $result,
            ));
        } catch (Exception $e) {
            Log::error('Bulut.matchFacilities error: ' . $e->getMessage());
            return response()->json(array('status' => false, 'message' => $e->getMessage()), 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Private: API yanıtındaki facilitylerle property_fact tablosunu eşleştir + logla
    // ─────────────────────────────────────────────────────────────────────────────
    private function matchAndLogFacilities(array $detail, $hotelId, $propertyId)
    {
        // ── 1. API'den facility isimlerini topla ──────────────────────────────────
        // getHotelFacilities yapısı: facilities[], accommodationHighlights[], highlights[]
        // getHotelDetails yapısı (eski): facilities_block.facilities[], top_ufi_benefits[], property_highlight_strip[]
        $apiNames = array();

        $addUniq = function ($name) use (&$apiNames) {
            $name = trim($name);
            if ($name !== '' && !in_array($name, $apiNames)) {
                $apiNames[] = $name;
            }
        };

        // getHotelFacilities → facilities[].instances[].title  (96 adet zengin veri)
        if (isset($detail['facilities']) && is_array($detail['facilities'])) {
            foreach ($detail['facilities'] as $fac) {
                if (!empty($fac['instances']) && is_array($fac['instances'])) {
                    foreach ($fac['instances'] as $inst) {
                        if (!empty($inst['title'])) {
                            $addUniq($inst['title']);
                        }
                    }
                }
            }
        }

        // getHotelFacilities → accommodationHighlights[].title
        if (isset($detail['accommodationHighlights']) && is_array($detail['accommodationHighlights'])) {
            foreach ($detail['accommodationHighlights'] as $h) {
                if (!empty($h['title'])) {
                    $addUniq($h['title']);
                }
            }
        }

        // getHotelFacilities → highlights[].instances[].title
        if (isset($detail['highlights']) && is_array($detail['highlights'])) {
            foreach ($detail['highlights'] as $h) {
                if (!empty($h['instances']) && is_array($h['instances'])) {
                    foreach ($h['instances'] as $inst) {
                        if (!empty($inst['title'])) {
                            $addUniq($inst['title']);
                        }
                    }
                }
            }
        }

        // getHotelDetails uyumluluğu — eski endpoint hâlâ çalışsın
        if (isset($detail['facilities_block']['facilities']) && is_array($detail['facilities_block']['facilities'])) {
            foreach ($detail['facilities_block']['facilities'] as $fac) {
                if (!empty($fac['name'])) {
                    $addUniq($fac['name']);
                }
            }
        }
        if (isset($detail['top_ufi_benefits']) && is_array($detail['top_ufi_benefits'])) {
            foreach ($detail['top_ufi_benefits'] as $ben) {
                if (!empty($ben['translated_name'])) {
                    $addUniq($ben['translated_name']);
                }
            }
        }
        if (isset($detail['property_highlight_strip']) && is_array($detail['property_highlight_strip'])) {
            foreach ($detail['property_highlight_strip'] as $strip) {
                if (!empty($strip['name'])) {
                    $addUniq($strip['name']);
                }
            }
        }

        $apiNames = array_values($apiNames);

        if (empty($apiNames)) {
            return array(
                'matched'   => array(),
                'unmatched' => array(),
                'message'   => 'API yanıtında facility bulunamadı',
            );
        }

        // ── 2. property_fact tablosundaki TÜM kayıtları çek ──────────────────────
        $allFacts   = PropertyFact::select(array('id', 'name', 'icon', 'parent_id', 'type'))->get();
        $exactIndex = array();
        foreach ($allFacts as $fact) {
            $key = mb_strtolower(trim($fact->name));
            if (!isset($exactIndex[$key]) || $fact->type == 1) {
                $exactIndex[$key] = $fact;
            }
        }

        // ── 3. Alias map — Booking.com adı ≠ DB adı olan terimler ───────────────
        $aliasMap = array(
            // Internet
            'internet services'                         => 'wi-fi',
            'free wifi'                                 => 'wi-fi',
            'wifi'                                      => 'wi-fi',
            'wi-fi'                                     => 'wi-fi',
            'wifi in all areas'                         => 'wi-fi',
            'free wi-fi'                                => 'wi-fi',
            'internet'                                  => 'wi-fi',
            'internet access'                           => 'wi-fi',
            // Ulaşım
            'airport shuttle'                           => 'airport transfer',
            'airport pick up'                           => 'airport to hotel transfer',
            'airport drop off'                          => 'hotel to airport transfer',
            'car hire'                                  => 'rent a car',
            'car rental'                                => 'rent a car',
            'shuttle service'                           => 'airport transfer',
            // Servis
            '24-hour front desk'                        => 'reception',
            'concierge service'                         => 'concierge',
            'luggage storage'                           => 'luggage storage',
            'laundry'                                   => 'cleaning service',
            'daily housekeeping'                        => 'housekeeping',
            'tour desk'                                 => 'tour desk',
            'private check-in/check-out'                => 'check-in service',
            'express check-in/check-out'                => 'check-in service',
            'wake-up service'                           => 'wake up service',
            'dry cleaning'                              => 'dry cleaning',
            'currency exchange'                         => 'currency exchange',
            // Engelli
            'facilities for disabled guests'            => 'disabled',
            'wheelchair accessible'                     => 'wheelchair',
            'upper floors accessible by elevator'       => 'elevator',
            'lower bathroom sink'                       => 'lower bathroom sink',
            'toilet with grab rails'                    => 'toilet with grab rails',
            // Yiyecek
            'breakfast'                                 => 'bed and breakfast',
            'snack bar'                                 => 'snack bar',
            'meeting/banquet facilities'                => 'meeting room',
            'business centre'                           => 'working area',
            'business center'                           => 'working area',
            'fax/photocopying'                          => 'photocopy',
            // Oda
            'air conditioning'                          => 'air conditioner',
            'flat-screen tv'                            => 'tv',
            'flat screen tv'                            => 'tv',
            'bath or shower'                            => 'shower',
            'free toiletries'                           => 'shower',
            'single-room air conditioning for guest accommodation' => 'air conditioner',
            'minibar'                                   => 'mini bar',
            'mini bar'                                  => 'mini bar',
            'hairdryer'                                 => 'hair dryer',
            'hair dryer'                                => 'hair dryer',
            'wardrobe or closet'                        => 'clothes cabinet',
            'socket near the bed'                       => 'planning electrical sockets',
            'family rooms'                              => 'family room',
            'clothes rack'                              => 'clotheshorse',
            // Güvenlik
            'cctv in common areas'                      => 'security camera',
            'cctv outside property'                     => 'security camera',
            'smoke alarms'                              => 'smoke alarm',
            'safety deposit box'                        => 'safety deposit box',
            '24-hour security'                          => 'security service',
            'key card access'                           => 'security service',
            // Hijyen
            'hand sanitizer in guest accommodation and key areas' => 'hand sanitiser',
            'hand sanitiser'                            => 'hand sanitiser',
            'face masks for guests available'           => 'protective masks for guests',
            'physical distancing rules followed'        => 'social distancing regulations',
            'screens or physical barriers placed between staff and guests in appropriate areas' => 'protective hygiene screens',
            'guest accommodation is disinfected between stays' => 'disinfection in all rooms',
            // Aktivite
            'tennis court'                              => 'tennis',
            'golf course'                               => 'golf',
            'table tennis'                              => 'ping pong',
            'jogging track'                             => 'jogging',
            // Çevre
            'lift'                                      => 'elevator',
            'elevator'                                  => 'elevator',
        );

        // ── 4. Eşleştir ───────────────────────────────────────────────────────────
        $matched   = array();
        $unmatched = array();

        foreach ($apiNames as $apiName) {
            $lower     = mb_strtolower(trim($apiName));
            $searchKey = isset($aliasMap[$lower]) ? $aliasMap[$lower] : $lower;

            // ADIM 1: Alias → exact
            if (isset($exactIndex[$searchKey])) {
                $fact      = $exactIndex[$searchKey];
                $tag       = ($searchKey !== $lower) ? 'alias' : 'exact';
                $matched[] = array(
                    'api_name'   => $apiName,
                    'fact_id'    => $fact->id,
                    'fact_name'  => $fact->name,
                    'match_type' => $tag,
                );
                continue;
            }

            // ADIM 2: DB LIKE — fact adı içinde api ismi geçiyor mu?
            $likeResult = PropertyFact::where('type', 1)
                ->whereRaw('LOWER(name) LIKE ?', array('%' . $lower . '%'))
                ->orderByRaw('LENGTH(name) ASC')
                ->first();

            if ($likeResult) {
                $matched[] = array(
                    'api_name'   => $apiName,
                    'fact_id'    => $likeResult->id,
                    'fact_name'  => $likeResult->name,
                    'match_type' => 'like',
                );
                continue;
            }

            // ADIM 3: Ters LIKE — fact adı api isminin içinde mi?
            $reverseResult = PropertyFact::where('type', 1)
                ->whereRaw('LOWER(?) LIKE CONCAT(\'%\', LOWER(name), \'%\')', array($lower))
                ->whereRaw('LENGTH(name) >= 5')
                ->orderByRaw('LENGTH(name) DESC')
                ->first();

            if ($reverseResult) {
                $matched[] = array(
                    'api_name'   => $apiName,
                    'fact_id'    => $reverseResult->id,
                    'fact_name'  => $reverseResult->name,
                    'match_type' => 'reverse_like',
                );
                continue;
            }

            $unmatched[] = $apiName;
        }

        // ── 5. storage/fact.log — okunabilir format ───────────────────────────────
        $logPath = storage_path('fact.log');
        $ts      = date('Y-m-d H:i:s');
        $divider = str_repeat('═', 80);
        $thin    = str_repeat('─', 80);

        $lines   = array();
        $lines[] = $divider;
        $lines[] = sprintf('  [%s]   hotel_id=%-12s property_id=%s', $ts, $hotelId, $propertyId);
        $lines[] = sprintf(
            '  Toplam API facility: %d  |  Eşleşen: %d  |  Eşleşmeyen: %d',
            count($apiNames),
            count($matched),
            count($unmatched)
        );
        $lines[] = $divider;
        $lines[] = '';

        $lines[] = sprintf('  EŞLEŞENLER  (%d)', count($matched));
        $lines[] = '  ' . $thin;
        if (count($matched)) {
            foreach ($matched as $m) {
                $lines[] = sprintf(
                    '  [%-12s]  %-45s  →  #%-5d  %s',
                    $m['match_type'],
                    '"' . $m['api_name'] . '"',
                    $m['fact_id'],
                    $m['fact_name']
                );
            }
        } else {
            $lines[] = '  (eşleşen yok)';
        }

        $lines[] = '';
        $lines[] = sprintf('  EŞLEŞMEYENLEr  (%d)', count($unmatched));
        $lines[] = '  ' . $thin;
        if (count($unmatched)) {
            foreach ($unmatched as $u) {
                $lines[] = '  [?]  ' . $u;
            }
        } else {
            $lines[] = '  (tümü eşleşti — property_fact\'e eklenebilir)';
        }

        $lines[] = '';
        $lines[] = '';

        file_put_contents($logPath, implode(PHP_EOL, $lines), FILE_APPEND | LOCK_EX);

        return array(
            'api_facilities_count' => count($apiNames),
            'matched_count'        => count($matched),
            'unmatched_count'      => count($unmatched),
            'matched'              => $matched,
            'unmatched'            => $unmatched,
            'log_file'             => $logPath,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // AI Semantic Match: getHotelFacilities → string match → kalan unmatched'ları
    // Gemini'ye gönder → "aynı kavram farklı isim mi?" veya "gerçekten eksik mi?"
    // GET /bulut/ai-match?hotel_id=...&property_id=...
    // ─────────────────────────────────────────────────────────────────────────────
    public function aiMatch(Request $request)
    {
        $hotelId    = $request->query('hotel_id', '');
        $propertyId = $request->query('property_id', 1);

        if (!$hotelId) {
            return response()->json(array('status' => false, 'message' => 'hotel_id gerekli'), 422);
        }

        $geminiKey = env('GEMINI_API_KEY', '');
        if (!$geminiKey) {
            return response()->json(array('status' => false, 'message' => 'GEMINI_API_KEY .env\'de tanımlı değil'), 500);
        }

        try {
            // ── ADIM 1: Booking.com'dan tüm faciliteleri çek ─────────────────────
            $response = $this->client()->get(
                self::API_BASE . '/api/v1/hotels/getHotelFacilities',
                array('query' => array('hotel_id' => $hotelId))
            );
            $data       = json_decode($response->getBody()->getContents(), true);
            $facilData  = isset($data['data']) ? $data['data'] : array();

            // Tüm API isimlerini topla
            $apiNames = array();
            $addUniq  = function ($name) use (&$apiNames) {
                $name = trim($name);
                if ($name !== '' && !in_array($name, $apiNames)) {
                    $apiNames[] = $name;
                }
            };

            if (isset($facilData['facilities']) && is_array($facilData['facilities'])) {
                foreach ($facilData['facilities'] as $fac) {
                    if (!empty($fac['instances']) && is_array($fac['instances'])) {
                        foreach ($fac['instances'] as $inst) {
                            if (!empty($inst['title'])) {
                                $addUniq($inst['title']);
                            }
                        }
                    }
                }
            }
            if (isset($facilData['accommodationHighlights']) && is_array($facilData['accommodationHighlights'])) {
                foreach ($facilData['accommodationHighlights'] as $h) {
                    if (!empty($h['title'])) {
                        $addUniq($h['title']);
                    }
                }
            }
            if (isset($facilData['highlights']) && is_array($facilData['highlights'])) {
                foreach ($facilData['highlights'] as $h) {
                    if (!empty($h['instances']) && is_array($h['instances'])) {
                        foreach ($h['instances'] as $inst) {
                            if (!empty($inst['title'])) {
                                $addUniq($inst['title']);
                            }
                        }
                    }
                }
            }

            if (empty($apiNames)) {
                return response()->json(array('status' => false, 'message' => 'API\'den facility alınamadı'), 500);
            }

            // ── ADIM 2: String tabanlı match (mevcut mantık) ─────────────────────
            $stringResult  = $this->matchAndLogFacilities($facilData, $hotelId, $propertyId);
            $stringMatched = $stringResult['matched'];
            $unmatched     = $stringResult['unmatched'];

            if (empty($unmatched)) {
                return response()->json(array(
                    'status'          => true,
                    'hotel_id'        => $hotelId,
                    'string_matched'  => $stringMatched,
                    'ai_matched'      => array(),
                    'truly_missing'   => array(),
                    'message'         => 'Tüm facilityler string eşleştirme ile bulundu, AI çağrısı gerekmedi',
                ));
            }

            // ── ADIM 3: DB'deki tüm fact isimlerini çek ──────────────────────────
            $allFactNames = PropertyFact::where('type', 1)
                ->orderBy('name')
                ->pluck('name', 'id')
                ->toArray();

            // Gemini'ye göndermek için isim → id lookup
            $nameToId = array();
            foreach ($allFactNames as $id => $name) {
                $nameToId[mb_strtolower(trim($name))] = array('id' => $id, 'name' => $name);
            }

            // ── ADIM 4: Gemini prompt ─────────────────────────────────────────────
            $unmatchedList = implode("\n", array_map(function ($n) {
                return '- ' . $n;
            }, $unmatched));
            $dbList        = implode("\n", array_map(function ($n) {
                return '- ' . $n;
            }, $allFactNames));

            $prompt = <<<PROMPT
You are a hotel facility semantic matching assistant.

I have two lists of hotel facility names.

LIST A - From Booking.com API (could not be matched by string comparison, need semantic analysis):
{$unmatchedList}

LIST B - From my hotel database (property_fact table, 708 entries):
{$dbList}

TASK: For each item in LIST A:
1. Check if there is a semantically equivalent entry in LIST B (same concept, just different wording). Examples:
   - "Family rooms" = "Family Room" → MATCH
   - "Wine/champagne" = "Wine Cellar" → MATCH (if exists in LIST B)
   - "City view" = "Sea View" → NO MATCH (different concepts)
   - "City view" = "City Centre" → NO MATCH (location ≠ view)
2. If there is a good semantic match, report it.
3. If there is absolutely no equivalent concept in LIST B, mark it as missing.

IMPORTANT: Only match when you are confident (≥80%) they refer to the same hotel facility/service. Do NOT stretch.

Return ONLY valid JSON (no markdown, no explanation):
{
  "ai_matches": [
    {"api_name": "...", "db_name": "...", "reason": "..."}
  ],
  "truly_missing": ["...", "..."]
}
PROMPT;

            // ── ADIM 5: Gemini API çağrısı ────────────────────────────────────────
            $geminiClient = new Client(array('timeout' => 60, 'http_errors' => false));

            // Sırayla farklı modeller dene (free tier kota sorunu için)
            $geminiModels = array(
                'gemini-2.0-flash-lite',
                'gemini-2.0-flash',
                'gemini-flash-lite-latest',
                'gemini-flash-latest',
            );

            $rawText    = null;
            $lastStatus = 0;

            foreach ($geminiModels as $model) {
                $geminiResponse = $geminiClient->post(
                    'https://generativelanguage.googleapis.com/v1beta/models/' . $model . ':generateContent?key=' . $geminiKey,
                    array(
                        'json' => array(
                            'contents' => array(
                                array('parts' => array(array('text' => $prompt)))
                            ),
                            'generationConfig' => array(
                                'responseMimeType' => 'application/json',
                                'temperature'      => 0.1,
                            ),
                        ),
                    )
                );

                $lastStatus = $geminiResponse->getStatusCode();

                if ($lastStatus === 200) {
                    $geminiBody = json_decode($geminiResponse->getBody()->getContents(), true);
                    $rawText    = isset($geminiBody['candidates'][0]['content']['parts'][0]['text'])
                        ? $geminiBody['candidates'][0]['content']['parts'][0]['text']
                        : null;
                    break;
                }

                // 429 = quota exceeded → bir sonraki modeli dene
                if ($lastStatus !== 429) {
                    $errBody = $geminiResponse->getBody()->getContents();
                    throw new Exception('Gemini API hatası (' . $model . '): HTTP ' . $lastStatus . ' → ' . substr($errBody, 0, 200));
                }
            }

            if ($rawText === null) {
                return response()->json(array(
                    'status'          => true,
                    'hotel_id'        => $hotelId,
                    'api_total'       => count($apiNames),
                    'string_matched'  => array('count' => count($stringMatched), 'matches' => $stringMatched),
                    'ai_matched'      => array('count' => 0, 'matches' => array()),
                    'truly_missing'   => array('count' => count($unmatched), 'items' => $unmatched),
                    'total_matched'   => count($stringMatched),
                    'warning'         => 'Tüm Gemini modelleri 429 quota hatası verdi. String match sonuçları döndürüldü. Birkaç dakika bekleyip tekrar deneyin.',
                ));
            }

            $aiResult = json_decode($rawText, true);
            if (!$aiResult) {
                $aiResult = array('ai_matches' => array(), 'truly_missing' => $unmatched);
            }

            $aiMatches     = isset($aiResult['ai_matches'])   ? $aiResult['ai_matches']   : array();
            $trulyMissing  = isset($aiResult['truly_missing']) ? $aiResult['truly_missing'] : array();

            // AI eşleşmelerine DB id'si ekle
            foreach ($aiMatches as $idx => $m) {
                $key = mb_strtolower(trim($m['db_name']));
                if (isset($nameToId[$key])) {
                    $aiMatches[$idx]['fact_id']   = $nameToId[$key]['id'];
                    $aiMatches[$idx]['fact_name']  = $nameToId[$key]['name'];
                    $aiMatches[$idx]['match_type'] = 'ai_semantic';
                }
            }

            // ── ADIM 6: off_fact.log — TÜM liste: var olanlar + olmayanlar ──────────
            $logPath = storage_path('off_fact.log');
            $ts      = date('Y-m-d H:i:s');
            $eq      = str_repeat('═', 90);
            $dash    = str_repeat('─', 90);

            // Tüm eşleşmeleri birleştir (string + AI)
            $allMatched = $stringMatched;
            foreach ($aiMatches as $am) {
                $allMatched[] = array(
                    'api_name'   => $am['api_name'],
                    'fact_id'    => isset($am['fact_id'])   ? $am['fact_id']   : '???',
                    'fact_name'  => isset($am['fact_name']) ? $am['fact_name'] : $am['db_name'],
                    'match_type' => 'ai_semantic',
                    'reason'     => isset($am['reason']) ? $am['reason'] : '',
                );
            }

            $logLines   = array();
            $logLines[] = $eq;
            $logLines[] = sprintf(
                '  [%s]   hotel_id: %-12s   property_id: %s',
                $ts,
                $hotelId,
                $propertyId
            );
            $logLines[] = sprintf(
                '  Booking.com\'dan gelen: %d  |  DB\'de VAR: %d  |  DB\'de YOK: %d',
                count($apiNames),
                count($allMatched),
                count($trulyMissing)
            );
            $logLines[] = $eq;
            $logLines[] = '';

            // ── VAR OLANLAR ───────────────────────────────────────────────────────
            $logLines[] = sprintf('  ✔  DB\'DE VAR  (%d / %d)', count($allMatched), count($apiNames));
            $logLines[] = '  ' . $dash;
            foreach ($allMatched as $m) {
                $type = isset($m['match_type']) ? $m['match_type'] : 'exact';
                $line = sprintf(
                    '  [%-12s]  %-50s  →  #%-5s  %s',
                    $type,
                    '"' . $m['api_name'] . '"',
                    $m['fact_id'],
                    $m['fact_name']
                );
                $logLines[] = $line;
                if (!empty($m['reason'])) {
                    $logLines[] = sprintf('               AI notu: %s', $m['reason']);
                }
            }

            $logLines[] = '';

            // ── YOK OLANLAR ───────────────────────────────────────────────────────
            $logLines[] = sprintf('  ✘  DB\'DE YOK  (%d / %d)  — property_fact\'e eklenmesi değerlendirilebilir', count($trulyMissing), count($apiNames));
            $logLines[] = '  ' . $dash;
            if (count($trulyMissing)) {
                foreach ($trulyMissing as $missing) {
                    $logLines[] = '  [MISSING]       "' . $missing . '"';
                }
            } else {
                $logLines[] = '  (tüm facilityler DB\'de mevcut)';
            }

            $logLines[] = '';
            $logLines[] = '';

            file_put_contents($logPath, implode(PHP_EOL, $logLines), FILE_APPEND | LOCK_EX);

            return response()->json(array(
                'status'         => true,
                'hotel_id'       => $hotelId,
                'api_total'      => count($apiNames),
                'string_matched' => array(
                    'count'   => count($stringMatched),
                    'matches' => $stringMatched,
                ),
                'ai_matched'     => array(
                    'count'   => count($aiMatches),
                    'matches' => $aiMatches,
                ),
                'truly_missing'  => array(
                    'count' => count($trulyMissing),
                    'items' => $trulyMissing,
                ),
                'total_matched'  => count($stringMatched) + count($aiMatches),
            ));
        } catch (Exception $e) {
            Log::error('Bulut.aiMatch error: ' . $e->getMessage());
            return response()->json(array('status' => false, 'message' => $e->getMessage()), 500);
        }
    }
}
