<?php

namespace App\Http\Controllers;

use App\Core\Service\PropertyService;
use App\Core\Service\PropertyContactService;
use App\Core\Service\PropertyFactService;
use App\Core\Service\PropertyFactMappingService;
use App\Core\Service\PropertyRoomService;
use App\Core\Service\UserService;
use App\Core\Service\UserPropertyMappingService;
use App\Core\Service\JwtService;
use App\Core\Service\ApiAccessTokenService;
use App\Core\Service\ProductService;
use App\Exceptions\ApiErrorException;
use App\Models\PropertyFact;
use App\Models\PropertyPhoto;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Intervention\Image\Facades\Image;

/**
 * propertyInsertController
 *
 * Booking.com'dan gelen otel verisiyle property oluşturma akışını
 * tek endpoint üzerinden uçtan uca çalıştırır.
 *
 * AKIŞ:
 *   ADIM 1 — Kullanıcı kaydı + property oluşturma  (user/register-user-with-property)
 *   ADIM 2 — Property bilgilerini güncelle           (property/info/update)
 *   ADIM 3 — İletişim bilgilerini kaydet             (property/contact/update)
 *   ADIM 4 — Facility eşleştir → fact-mapping ekle  (property/fact-mapping/add)
 *   ADIM 5 — Oda ekle                               (property/room/add-room-bed)
 *
 * KULLANIM:
 *   POST /bulut/property-insert
 *   {
 *     "hotel_id"       : "89675",           // Booking.com hotel_id (zorunlu)
 *     "email"          : "owner@hotel.com", // kullanıcı e-posta (zorunlu)
 *     "password"       : "Abc123!",         // kullanıcı şifre (zorunlu)
 *     "name"           : "Ahmet",           // kullanıcı adı (zorunlu)
 *     "surname"        : "Yılmaz",          // kullanıcı soyadı (zorunlu)
 *     "property_name"  : "Grand Yavuz",     // property adı (zorunlu)
 *     "phone"          : "+90...",          // iletişim telefonu (opsiyonel)
 *     "dry_run"        : false              // true → DB'ye yazma, sadece rapor üret
 *   }
 */
class propertyInsertController extends Controller
{
    const API_HOST = 'booking-com15.p.rapidapi.com';
    const API_BASE = 'https://booking-com15.p.rapidapi.com';

    // ─────────────────────────────────────────────────────────────────────────────
    // Alias map: Booking.com facility adı → property_fact.name (küçük harf)
    // ─────────────────────────────────────────────────────────────────────────────
    private $aliasMap = array(
        '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',
        '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',
        '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',
        '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',
        'breakfast'                                  => 'bed and breakfast',
        'snack bar'                                  => 'snack bar',
        'meeting/banquet facilities'                 => 'meeting room',
        'business centre'                            => 'working area',
        'business center'                            => 'working area',
        'fax/photocopying'                           => 'photocopy',
        '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',
        'single-room ac for guest accommodation'     => 'air conditioner',
        'minibar'                                    => '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',
        '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',
        'hand sanitizer in guest accommodation and key areas' => 'hand sanitiser',
        'hand sanitiser'                             => 'hand sanitiser',
        'hand sanitizer'                             => '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',
        'cashless payment available'                 => 'contactless payment',
        'food can be delivered to guest accommodation' => 'food delivery',
        'tennis court'                               => 'tennis',
        'golf course'                                => 'golf',
        'table tennis'                               => 'ping pong',
        'jogging track'                              => 'jogging',
        'lift'                                       => 'elevator',
        'elevator'                                   => 'elevator',
    );

    // ─────────────────────────────────────────────────────────────────────────────
    // Oda olanaklarına özel alias: Booking.com oda facility adı → property_fact.name
    // ─────────────────────────────────────────────────────────────────────────────
    private $roomAliasMap = array(
        'safe'                 => 'safe box',
        'towels'               => 'towel',
        'linens'               => 'towel',
        'tea/coffee maker'     => 'coffee maker',
        'coffee/tea maker'     => 'coffee maker',
        'electric kettle'      => 'kettle',
        'private bathroom'     => 'bathroom',
        'telephone'            => 'telephone',
        'toilet paper'         => 'toilet',
        'free toiletries'      => 'hair dryer',
        'slippers'             => 'bathrobe',
        'bath or shower'       => 'shower',
        'bathtub or shower'    => 'shower',
        'shower only'          => 'shower',
    );

    // ─────────────────────────────────────────────────────────────────────────────
    // GuzzleHttp → Booking.com API
    // ─────────────────────────────────────────────────────────────────────────────
    private function bookingClient()
    {
        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 0: Booking.com'dan otel verilerini çek
    // ─────────────────────────────────────────────────────────────────────────────
    private function fetchBookingData($hotelId, $checkin, $checkout)
    {
        $client = $this->bookingClient();

        // Otel detayı (property bilgileri: isim, konum, dil, timezone vb.)
        $detailResp = $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',
            ),
        ));
        $detail = json_decode($detailResp->getBody()->getContents(), true);
        $detail = isset($detail['data']) ? $detail['data'] : array();

        // Oda listesi — tüm oda tiplerini çek (getRoomList daha kapsamlı)
        // getHotelDetails sadece o güne müsait odaları döndürür, getRoomList tüm tipleri verir
        $checkinRooms  = date('Y-m-d', strtotime('+30 days'));
        $checkoutRooms = date('Y-m-d', strtotime('+37 days'));
        $roomListResp = $client->get(self::API_BASE . '/api/v1/hotels/getRoomList', array(
            'query' => array(
                'hotel_id'      => $hotelId,
                'arrival_date'  => $checkinRooms,
                'departure_date' => $checkoutRooms,
                'adults'        => 2,
                'room_qty'      => 1,
                'currency_code' => 'EUR',
                'languagecode'  => 'en-us',
            ),
        ));
        $roomListData = json_decode($roomListResp->getBody()->getContents(), true);
        $roomListData = isset($roomListData['data']) ? $roomListData['data'] : array();

        // getRoomList'ten gelen block[] ve rooms[] ile detail'i zenginleştir
        if (!empty($roomListData['block'])) {
            $detail['block'] = $roomListData['block'];
        }
        if (!empty($roomListData['rooms'])) {
            $detail['rooms'] = $roomListData['rooms'];
        }

        // Facility listesi
        $facilResp = $client->get(self::API_BASE . '/api/v1/hotels/getHotelFacilities', array(
            'query' => array('hotel_id' => $hotelId),
        ));
        $facilData = json_decode($facilResp->getBody()->getContents(), true);
        $facilData = isset($facilData['data']) ? $facilData['data'] : array();

        // Otel fotograflari
        $photoResp = $client->get(self::API_BASE . '/api/v1/hotels/getHotelPhotos', array(
            'query' => array('hotel_id' => $hotelId),
        ));
        $photoData = json_decode($photoResp->getBody()->getContents(), true);

        return array('detail' => $detail, 'facilities' => $facilData, 'photos' => $photoData);
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 1: Kullanıcı + Property oluştur
    //         → user/register-user-with-property mantığı
    // ─────────────────────────────────────────────────────────────────────────────
    private function createUserAndProperty(array $params, $propertyName, $userId = null)
    {
        // Kullanıcı zaten varsa sadece property ekle
        $userService                = app(\App\Core\Service\UserService::class);
        $propertyService            = app(\App\Core\Service\PropertyService::class);
        $userPropertyMappingService = app(\App\Core\Service\UserPropertyMappingService::class);
        $productService             = app(\App\Core\Service\ProductService::class);
        $jwtService                 = app(\App\Core\Service\JwtService::class);
        $apiAccessTokenService      = app(\App\Core\Service\ApiAccessTokenService::class);

        // Kullanıcı oluştur
        $userParams = array(
            'name'          => $params['name'],
            'surname'       => $params['surname'],
            'email'         => $params['email'],
            'password'      => $params['password'],
            'status'        => 1,
            'user_type'     => 1,
            'property_name' => $propertyName,
        );
        $userCreate = $userService->create($userParams);
        if ($userCreate['status'] != 'success') {
            throw new ApiErrorException('Kullanıcı oluşturulamadı: ' . $userCreate['message']);
        }
        $user = $userCreate['data'];

        // UserService::create rastgele şifre üretiyor (Str::random(6))
        // Kullanıcının istediği şifreyi DB'ye doğrudan güncelle
        DB::table('user')
            ->where('id', $user['id'])
            ->update(array('password' => \Illuminate\Support\Facades\Hash::make($params['password'])));

        // Property oluştur
        $propertyCreate = $propertyService->create(array(
            'name'       => $propertyName,
            'status'     => 1,
            'created_by' => $user['id'],
            'updated_by' => $user['id'],
            'created_at' => time(),
            'updated_at' => time(),
        ));
        if ($propertyCreate['status'] != 'success') {
            throw new ApiErrorException('Property oluşturulamadı: ' . $propertyCreate['message']);
        }
        $property = $propertyCreate['data'];

        // User-Property mapping
        $mappingCreate = $userPropertyMappingService->create(array(
            'user_id'     => $user['id'],
            'property_id' => $property['id'],
            'status'      => 1,
            'created_by'  => $user['id'],
            'updated_by'  => $user['id'],
            'created_at'  => time(),
            'updated_at'  => time(),
        ));
        if ($mappingCreate['status'] != 'success') {
            throw new ApiErrorException('Kullanıcı-Property eşleştirme hatası: ' . $mappingCreate['message']);
        }

        // Default ürünleri ata
        $productService->setDefaultPropertyProducts(array(
            'user_id'     => $user['id'],
            'property_id' => $property['id'],
        ));

        // JWT token al
        $jwtResult = $jwtService->jwtCreate(array('user_id' => $user['id']));
        if ($jwtResult['status'] != 'success') {
            throw new ApiErrorException('Token oluşturulamadı');
        }
        $jwt = $jwtResult['data'];

        $apiAccessTokenService->create(array(
            'token'       => md5(fillOnUndefined($jwt, 'token')),
            'expire_date' => fillOnUndefined($jwt, 'exp'),
            'user_id'     => $user['id'],
            'invalidate'  => fillOnUndefined($jwt, 'invalidate', 0),
        ));

        return array(
            'user'        => $user,
            'property_id' => $property['id'],
            'token'       => $jwt['token'],
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 2: Property bilgilerini güncelle
    //         → property/info/update
    //         Booking.com detail → property_info, additional_info, locale
    // ─────────────────────────────────────────────────────────────────────────────
    private function updatePropertyInfo($propertyId, $userId, array $detail)
    {
        $propertyService = app(\App\Core\Service\PropertyService::class);

        $name    = isset($detail['hotel_name']) ? $detail['hotel_name'] : null;
        $raw     = isset($detail['rawData'])    ? $detail['rawData']    : array();

        // Stars: rawData.accuratePropertyClass > rawData.propertyClass > rawData.qualityClass
        $rating = null;
        foreach (array('accuratePropertyClass', 'propertyClass', 'qualityClass') as $rk) {
            if (!empty($raw[$rk])) {
                $rating = (int) $raw[$rk];
                break;
            }
        }

        // Check-in/out: rawData.checkin.fromTime / rawData.checkout.untilTime
        $checkIn  = isset($raw['checkin']['fromTime'])   ? $raw['checkin']['fromTime']   : null;
        $checkOut = isset($raw['checkout']['untilTime']) ? $raw['checkout']['untilTime'] : null;

        // Ülke kodu (max 5 char)
        $countryCode = null;
        foreach (array('countryCode', 'countrycode', 'country_code') as $ck) {
            if (!empty($raw[$ck])) {
                $countryCode = strtoupper($raw[$ck]);
                break;
            }
        }
        if (!$countryCode && !empty($detail['countrycode'])) {
            $countryCode = strtoupper($detail['countrycode']);
        }

        // Konuşulan diller: "en-gb" → "en_gb", "tr" → "tr"
        $spokenRaw  = isset($detail['spoken_languages']) ? $detail['spoken_languages'] : array('en');
        $langCodes  = array();
        foreach ($spokenRaw as $lang) {
            $normalized = str_replace('-', '_', strtolower($lang));
            // Sadece 2 veya 5 harfli geçerli kodlar
            if (preg_match('/^[a-z]{2}(_[a-z]{2})?$/', $normalized)) {
                $langCodes[] = $normalized;
            }
        }
        if (empty($langCodes)) {
            $langCodes = array('en');
        }

        $updateParams = array(
            'property_id'              => $propertyId,
            'user_id'                  => $userId,
            'locale'                   => 'en',
            'has_locale_name'          => false,
            'property_language_spoken' => $langCodes,
            'property_info'            => array(
                'name'             => $name,
                'property_type_id' => 1,   // 1 = Hotel
                'chain_id'         => 1,   // 1 = Independent
                'rating'           => $rating,
                'country'          => $countryCode,
            ),
            'additional_info' => array(
                'checkin_time'    => $checkIn,
                'checkout_time'   => $checkOut,
                'number_of_rooms' => !empty($detail['number_of_rooms']) ? (string)$detail['number_of_rooms'] : null,
                'property_timezone' => !empty($detail['timezone'])
                    ? $this->resolveTimezoneId($detail['timezone'])
                    : null,
            ),
        );

        $result = $propertyService->propertyUpdate($updateParams);
        if ($result['status'] != 'success') {
            throw new ApiErrorException('Property güncelleme hatası: ' . $result['message']);
        }

        return $result['data'];
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 3: İletişim bilgilerini kaydet
    //         → property/contact/update
    // ─────────────────────────────────────────────────────────────────────────────
    private function updatePropertyContact($propertyId, $userId, array $detail, $phone = null)
    {
        $propertyContactService = app(\App\Core\Service\PropertyContactService::class);

        // Booking.com top-level alanlar
        $email   = isset($detail['email'])     ? $detail['email']     : null;
        $web     = isset($detail['url'])       ? $detail['url']       : null;
        $address = isset($detail['address'])   ? $detail['address']   : null;
        $zip     = isset($detail['zip'])       ? $detail['zip']       : null;
        $lat     = isset($detail['latitude'])  ? $detail['latitude']  : null;
        $lng     = isset($detail['longitude']) ? $detail['longitude'] : null;

        if (!$phone && isset($detail['phone'])) {
            $phone = $detail['phone'];
        }

        // Validator: email required|email — boşsa placeholder kullan
        if (!$email) {
            $email = 'property' . $propertyId . '@extranetwork.com';
        }

        // Validator: phone veya mobile gerekli
        if (!$phone) {
            $phone = '0000000000';
        }

        $contactParams = array(
            'property_id' => $propertyId,
            'user_id'     => $userId,
            'contact'     => array(
                'phone'     => $phone,
                'email'     => $email,
                'web'       => $web,
                'address'   => $address,
                'zip_code'  => $zip,
                'latitude'  => $lat,
                'longitude' => $lng,
            ),
        );

        $result = $propertyContactService->propertyContactUpdateOrCreate($contactParams);
        if ($result['status'] != 'success') {
            throw new ApiErrorException('İletişim kaydetme hatası: ' . $result['message']);
        }

        return $result['data'];
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 4: Facility eşleştir → property_fact_mapping'e ekle
    //         → property/fact-mapping/add
    // ─────────────────────────────────────────────────────────────────────────────
    private function mapAndSaveFacilities($propertyId, $userId, array $facilData)
    {
        $propertyFactMappingService = app(\App\Core\Service\PropertyFactMappingService::class);

        // 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'])) {
                    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'])) {
                    foreach ($h['instances'] as $inst) {
                        if (!empty($inst['title'])) {
                            $addUniq($inst['title']);
                        }
                    }
                }
            }
        }

        // DB exact index
        $allFacts   = PropertyFact::select(array('id', 'name', 'type'))->get();
        $exactIndex = array();
        foreach ($allFacts as $fact) {
            $key = mb_strtolower(trim($fact->name));
            if (!isset($exactIndex[$key]) || $fact->type == 1) {
                $exactIndex[$key] = $fact;
            }
        }

        $saved    = array();
        $skipped  = array();

        foreach ($apiNames as $apiName) {
            $lower     = mb_strtolower(trim($apiName));
            $searchKey = isset($this->aliasMap[$lower]) ? $this->aliasMap[$lower] : $lower;
            $fact      = null;
            $matchType = 'none';

            // 1. Exact / alias
            if (isset($exactIndex[$searchKey])) {
                $fact      = $exactIndex[$searchKey];
                $matchType = ($searchKey !== $lower) ? 'alias' : 'exact';
            }

            // 2. DB LIKE
            if (!$fact) {
                $like = PropertyFact::where('type', 1)
                    ->whereRaw('LOWER(name) LIKE ?', array('%' . $lower . '%'))
                    ->orderByRaw('LENGTH(name) ASC')
                    ->first();
                if ($like) {
                    $fact      = $like;
                    $matchType = 'like';
                }
            }

            // 3. Ters LIKE
            if (!$fact) {
                $reverse = PropertyFact::where('type', 1)
                    ->whereRaw('LOWER(?) LIKE CONCAT(\'%\', LOWER(name), \'%\')', array($lower))
                    ->whereRaw('LENGTH(name) >= 5')
                    ->orderByRaw('LENGTH(name) DESC')
                    ->first();
                if ($reverse) {
                    $fact      = $reverse;
                    $matchType = 'reverse_like';
                }
            }

            if ($fact) {
                // Kaydet
                $mappingResult = $propertyFactMappingService->addPropertyFactMapping(array(
                    'property_id' => $propertyId,
                    'user_id'     => $userId,
                    'data'        => array(
                        array('id' => $fact->id),
                    ),
                ));
                $saved[] = array(
                    'api_name'   => $apiName,
                    'fact_id'    => $fact->id,
                    'fact_name'  => $fact->name,
                    'match_type' => $matchType,
                    'saved'      => ($mappingResult['status'] == 'success'),
                );
            } else {
                $skipped[] = $apiName;
            }
        }

        return array(
            'api_total'    => count($apiNames),
            'saved_count'  => count($saved),
            'skipped_count' => count($skipped),
            'saved'        => $saved,
            'skipped'      => $skipped,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 5: Booking.com'daki oda bilgilerinden oda ekle
    //         → property/room/add-room-bed
    // ─────────────────────────────────────────────────────────────────────────────
    // ─────────────────────────────────────────────────────────────────────────────
    // Booking.com bed_type ID → sistemdeki property_room_bed_type.id
    //
    // Booking.com standart IDs (DataCrawler API):
    //   1=Twin  2=Double  3=King  4=Queen  5=Single  6=Sofa  7=Bunk  8=Futon
    // Sistemdeki property_room_bed_type:
    //   1=Bunk Bed  2=Double Bed  3=French Bed  4=Futon  5=King Bed
    //   6=Queen Bed  7=Single Bed  8=Sofa Bed  9=Twin Bed  10=Foldable Bed
    //   11=Sleeping Bag  12=Triple Bunk Bed  13=Extra bed  14=Cot
    // ─────────────────────────────────────────────────────────────────────────────
    private $bedTypeMap = array(
        1  => 9,  // Twin Bed(s)   → Twin Bed
        2  => 2,  // Double Bed    → Double Bed
        3  => 5,  // King Bed      → King Bed
        4  => 6,  // Queen Bed     → Queen Bed
        5  => 7,  // Single Bed    → Single Bed
        6  => 8,  // Sofa Bed      → Sofa Bed
        7  => 1,  // Bunk Bed      → Bunk Bed
        8  => 4,  // Futon         → Futon
        9  => 3,  // French Bed    → French Bed
        10 => 10, // Foldable Bed  → Foldable Bed
        37 => 14, // Cot/Cribs     → Cot
        40 => 13, // Extra Bed     → Extra bed
    );

    // ─────────────────────────────────────────────────────────────────────────────
    // Booking.com view adı (highlight.translated_name) → property_room_view_type.id
    // ─────────────────────────────────────────────────────────────────────────────
    private $viewTypeMap = array(
        'park view'        => 1,
        'pool view'        => 2,
        'river view'       => 3,
        'sea view'         => 4,
        'ocean view'       => 22,
        'street view'      => 5,
        'valley view'      => 6,
        'monument view'    => 7,
        'bay view'         => 8,
        'beach view'       => 9,
        'city view'        => 10,
        'countryside view' => 11,
        'courtyard view'   => 12,
        'garden view'      => 13,
        'gulf view'        => 14,
        'harbor view'      => 15,
        'lagoon view'      => 16,
        'lake view'        => 17,
        'marina view'      => 18,
        'mountain view'    => 19,
        'nature view'      => 20,
        'no window'        => 21,
        'land view'        => 23,
        'forest view'      => 24,
        'island view'      => 25,
        'golf course view' => 26,
        'landmark view'    => 30,
        'sea view'         => 4,
    );

    // ─────────────────────────────────────────────────────────────────────────────
    // Booking.com oda adı keyword → property_room_type.id
    // ─────────────────────────────────────────────────────────────────────────────
    private $roomTypeKeywords = array(
        'standard'   => 24, // Standard Room
        'standart'   => 24,
        'single'     => 42, // Single Room
        'double'     => 43, // Double Room
        'twin'       => 43, // Double Room (çoğu twin=double planı)
        'triple'     => 44, // Triple Room
        'quad'       => 45, // Quadruple Room
        'family'     => 18, // Family Room
        'suite'      => 25, // Suite
        'junior suite' => 20,
        'grand suite'  => 19,
        'king suite'   => 21,
        'deluxe'     => 16, // Deluxe
        'superior'   => 26, // Superior
        'executive'  => 48, // Executive Room
        'villa'      => 27, // Villa
        'bungalow'   => 14, // Bungalow
        'loft'       => 31, // Loft Room
        'studio'     => 29, // Studio Room
        'apart'      => 12, // Apartment
        'apartment'  => 12,
        'penthouse'  => 22, // Pent House
        'accessible' => 11, // Accessible Room
        'honeymoon'  => 34, // Honeymoon Room
        'economy'    => 17, // Economy
        'premium'    => 23, // Premium Room
        'club'       => 15, // Club Room
        'swim up'    => 46, // Swim Up Room
        'swim-up'    => 46,
        'corner'     => 49, // Corner Room
        'large'      => 47, // Standard Large Room
    );

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 5: Booking.com'daki oda bilgilerinden oda ekle
    //
    // Kaynak 1: detail['block'][]     → room_name, max_occupancy, nr_adults,
    //                                   room_surface_in_m2, number_of_bathrooms
    // Kaynak 2: detail['rooms'][id]   → bed_configurations, highlights (view)
    // ─────────────────────────────────────────────────────────────────────────────
    private function insertRooms($propertyId, $userId, array $detail)
    {
        $propertyRoomService = app(\App\Core\Service\PropertyRoomService::class);

        // ── Kaynak 1: block[] → her room_id için tek kayıt ──────────────────────
        $blockByRoomId = array();
        $blockRaw = isset($detail['block']) ? $detail['block'] : array();
        foreach ($blockRaw as $b) {
            $rid = isset($b['room_id']) ? $b['room_id'] : null;
            if ($rid && !isset($blockByRoomId[$rid])) {
                $blockByRoomId[$rid] = $b;
            }
        }

        // ── Kaynak 2: rooms[room_id] → bed configs + view highlights ────────────
        $roomsRaw = isset($detail['rooms']) ? $detail['rooms'] : array();

        // rooms[] boşsa sadece block verisini kullan
        if (empty($roomsRaw) && empty($blockByRoomId)) {
            // Hiç oda yoksa tek generic oda
            $blockByRoomId = array(
                0 => array(
                    'room_name'          => 'Standard Room',
                    'max_occupancy'      => 2,
                    'nr_adults'          => 2,
                    'room_surface_in_m2' => null,
                    'number_of_bathrooms' => null,
                ),
            );
        }

        // rooms[] boşsa block ID'lerini rooms olarak kullan
        if (empty($roomsRaw)) {
            foreach ($blockByRoomId as $rid => $b) {
                $roomsRaw[$rid] = array();
            }
        }
        if (empty($blockByRoomId)) {
            foreach (array_keys($roomsRaw) as $rid) {
                $blockByRoomId[$rid] = array();
            }
        }

        // Distinct room_id birleşimi
        $allRoomIds = array_unique(array_merge(array_keys($blockByRoomId), array_keys($roomsRaw)));

        $inserted = array();

        foreach ($allRoomIds as $roomId) {
            $block = isset($blockByRoomId[$roomId]) ? $blockByRoomId[$roomId] : array();
            $room  = isset($roomsRaw[$roomId])      ? $roomsRaw[$roomId]      : array();

            // ── Oda adı ──────────────────────────────────────────────────────────
            $roomName = trim(isset($block['room_name']) ? $block['room_name'] : 'Standard Room');

            // ── room_type_id: oda adındaki anahtar kelimeye göre ─────────────────
            $roomTypeId = $this->guessRoomTypeId($roomName);

            // ── Kapasite ─────────────────────────────────────────────────────────
            $maxOccupancy = isset($block['max_occupancy']) ? (int)$block['max_occupancy'] : 2;
            $maxAdult     = isset($block['nr_adults'])     ? (int)$block['nr_adults']     : $maxOccupancy;
            $maxChild     = isset($block['nr_children'])   ? (int)$block['nr_children']   : 0;

            // ── Oda boyutu ───────────────────────────────────────────────────────
            // Validator required|max:30 → null yerine 0 gönder
            $roomSizeRaw  = isset($block['room_surface_in_m2']) ? (int)$block['room_surface_in_m2'] : 0;
            $roomSize     = $roomSizeRaw > 0 ? $roomSizeRaw : 0;
            $roomSizeType = $roomSizeRaw > 0 ? 1 : 0; // 1 = m²

            // ── Oda adedi (kaç adet bu tipten var) ──────────────────────────────
            $roomTypeCount = isset($block['room_count']) && $block['room_count'] > 0
                ? (int)$block['room_count'] : 1;

            // ── Banyo sayısı ─────────────────────────────────────────────────────
            $bathroomCount = isset($block['number_of_bathrooms']) && $block['number_of_bathrooms'] > 0
                ? (int)$block['number_of_bathrooms'] : null;

            // ── Açıklama ─────────────────────────────────────────────────────────
            $description = isset($room['description']) ? $room['description'] : null;

            // ── Yatak konfigürasyonları → room_bed_group ─────────────────────────
            // Sistem formatı: [[{bed_type_id:9}, {bed_type_id:9}], [{bed_type_id:2}]]
            // Her conf = bir grup, içindeki bed_types[].count kadar tekrar
            $bedConfigs = isset($room['bed_configurations']) ? $room['bed_configurations'] : array();
            $roomBedGroup = array();

            foreach ($bedConfigs as $conf) {
                $groupBeds = array();
                $bedTypes  = isset($conf['bed_types']) ? $conf['bed_types'] : array();
                foreach ($bedTypes as $bt) {
                    $bookingBedId  = isset($bt['bed_type']) ? (int)$bt['bed_type'] : 0;
                    $ourBedTypeId  = isset($this->bedTypeMap[$bookingBedId]) ? $this->bedTypeMap[$bookingBedId] : null;
                    $bedCount      = isset($bt['count']) ? (int)$bt['count'] : 1;
                    if ($ourBedTypeId) {
                        for ($i = 0; $i < $bedCount; $i++) {
                            $groupBeds[] = array('bed_type_id' => $ourBedTypeId);
                        }
                    }
                }
                if (!empty($groupBeds)) {
                    $roomBedGroup[] = $groupBeds;
                }
            }

            // ── View tipleri → room_view_type ────────────────────────────────────
            // Booking.com highlights'daki "translated_name" → viewTypeMap eşleşmesi
            // Eşleşmezse icon'a bak: "city"→10, "sea"→4, "pool"→2, "mountain"→19
            $iconViewMap = array(
                'city'     => 10,
                'sea'      => 4,
                'ocean'    => 22,
                'pool'     => 2,
                'mountain' => 19,
                'garden'   => 13,
                'park'     => 1,
                'river'    => 3,
                'lake'     => 17,
                'beach'    => 9,
                'forest'   => 24,
                'harbor'   => 15,
                'marina'   => 18,
                'eye'      => 4,      // Booking.com Sea view ikonu "eye" olarak geliyor
                'landmark' => 30,     // Landmark view
            );
            $highlights   = isset($room['highlights']) ? $room['highlights'] : array();
            $roomViewType = array();
            foreach ($highlights as $h) {
                $hName    = mb_strtolower(trim(isset($h['translated_name']) ? $h['translated_name'] : ''));
                $hIcon    = mb_strtolower(trim(isset($h['icon']) ? $h['icon'] : ''));
                $viewId   = null;
                // 1) Tam eşleşme: "city view"
                if (isset($this->viewTypeMap[$hName])) {
                    $viewId = $this->viewTypeMap[$hName];
                }
                // 2) Kısmi eşleşme: highlight adında keyword geçiyor
                if (!$viewId) {
                    foreach ($this->viewTypeMap as $keyword => $vid) {
                        $base = str_replace(' view', '', $keyword);
                        if (strpos($hName, $base) !== false) {
                            $viewId = $vid;
                            break;
                        }
                    }
                }
                // 3) Icon eşleşmesi: "city" ikonu → 10
                if (!$viewId && isset($iconViewMap[$hIcon])) {
                    $viewId = $iconViewMap[$hIcon];
                }
                if ($viewId && !in_array($viewId, $roomViewType)) {
                    $roomViewType[] = $viewId;
                }
            }

            // ── Service'e gönder ─────────────────────────────────────────────────
            $roomParams = array(
                'property_id'       => $propertyId,
                'user_id'           => $userId,
                'locale'            => 'en',
                'name'              => $roomName,
                'room_type_id'      => $roomTypeId,
                'max_occupancy'     => $maxOccupancy,
                'max_adult'         => $maxAdult,
                'max_child'         => $maxChild,
                'occupancy_lock'    => 0,
                'exclude_occupancy' => 0,
                'room_size'         => $roomSize,
                'room_size_type'    => $roomSizeType,
                'room_type_count'   => $roomTypeCount,
                'bathroom_count'    => $bathroomCount,
                'toilet_count'      => null,
                'lounge_count'      => null,
                'room_count'        => null,
                'max_child_number'  => null,
                'description'       => array(
                    array('language_code' => 'en', 'description' => $description)
                ),
                'room_bed_group'    => $roomBedGroup,
                'room_view_type'    => $roomViewType,
                'is_connected_room' => null,
                'is_connected_room_price' => null,
                'is_connected_room_availability' => null,
                'connected_rooms'   => array(),
            );

            $result = $propertyRoomService->addPropertyRoomAndBed($roomParams);
            $isSaved      = ($result['status'] == 'success' || $result['status'] === true);
            $facSummary   = array();
            $photoSummary = array();

            if ($isSaved) {
                // addPropertyRoomAndBed data döndürmüyor — son eklenen room_id'yi çek
                $newRoom = DB::table('property_room')
                    ->where('property_id', $propertyId)
                    ->where('name', $roomName)
                    ->orderBy('id', 'desc')
                    ->first();
                $newRoomId = $newRoom ? $newRoom->id : null;

                if ($newRoomId) {
                    // Oda olanakları → property_room_fact_mapping
                    if (!empty($room['facilities'])) {
                        $facSummary = $this->mapAndSaveRoomFacilities(
                            $newRoomId,
                            $propertyId,
                            $userId,
                            $room['facilities']
                        );
                    }

                    // Oda fotoğrafları → property_photo + property_room_photo_mapping
                    if (!empty($room['photos'])) {
                        $photoSummary = $this->mapAndSaveRoomPhotos(
                            $newRoomId,
                            $propertyId,
                            $userId,
                            $room['photos'],
                            isset($detail['hotel_id']) ? $detail['hotel_id'] : 0
                        );
                    }
                }
            }

            $inserted[] = array(
                'room_id'       => $roomId,
                'room_name'     => $roomName,
                'room_type_id'  => $roomTypeId,
                'beds'          => array_map(function ($g) {
                    return $g;
                }, $roomBedGroup),
                'views'         => $roomViewType,
                'room_facts'    => $facSummary,
                'room_photos'   => $photoSummary,
                'saved'         => $isSaved,
                'message'       => !$isSaved ? $result['message'] : null,
            );
        }

        return array(
            'room_count' => count($inserted),
            'rooms'      => $inserted,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Oda fotoğraflarını indir, property_photo'ya kaydet, room_photo_mapping'e bağla
    // Booking.com: rooms[id]['photos'] → [{url_original, url_max750, ...}]
    // ─────────────────────────────────────────────────────────────────────────────
    private function mapAndSaveRoomPhotos($roomId, $propertyId, $userId, array $photos, $hotelId)
    {
        if (empty($photos)) {
            return array('saved_count' => 0, 'skipped_count' => 0);
        }

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

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

        $saved   = array();
        $skipped = array();
        $index   = 0;

        foreach ($photos as $photo) {
            // URL: url_original > url_max750 > url_max1280 > url_max300
            $url = '';
            foreach (array('url_original', 'url_max750', 'url_max1280', 'url_max300') as $key) {
                if (!empty($photo[$key])) {
                    $url = $photo[$key];
                    break;
                }
            }
            if ($url === '') {
                $skipped[] = 'empty_url';
                continue;
            }

            try {
                $photoId  = isset($photo['photo_id']) ? $photo['photo_id'] : '';
                $fileName = time() . '_bk' . $hotelId . '_r' . $roomId . '_' . $index;
                $fileExt  = 'jpg';
                $tempPath = sys_get_temp_dir() . '/' . $fileName . '_orig.jpg';

                $this->downloadRawImage($url, $tempPath);

                $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);

                if (File::exists($tempPath)) {
                    File::delete($tempPath);
                }

                $isCompatible = ($imageWidth >= 1150 && $imageHeight >= 600) ? 1 : 0;

                $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'                      => 0,
                    '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(),
                ));

                // property_room_photo_mapping'e bağla
                $alreadyLinked = DB::table('property_room_photo_mapping')
                    ->where('room_id', $roomId)
                    ->where('photo_id', $photoRecord->id)
                    ->exists();

                if (!$alreadyLinked) {
                    DB::table('property_room_photo_mapping')->insert(array(
                        'property_id' => $propertyId,
                        'room_id'     => $roomId,
                        'photo_id'    => $photoRecord->id,
                        'created_by'  => $userId,
                        'updated_by'  => $userId,
                        'created_at'  => time(),
                        'updated_at'  => time(),
                    ));
                }

                $saved[] = array(
                    'photo_id'   => $photoRecord->id,
                    'file_name'  => $fileName . '.' . $fileExt,
                    'resolution' => $imageWidth . 'x' . $imageHeight,
                    'source_url' => $url,
                );
            } catch (Exception $e) {
                Log::error('propertyInsert.roomPhoto [room=' . $roomId . ', i=' . $index . ']: ' . $e->getMessage());
                $skipped[] = $url;
            }

            $index++;
        }

        return array(
            'saved_count'   => count($saved),
            'skipped_count' => count($skipped),
            'photos'        => $saved,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Oda olanaklarını (room facilities) property_room_fact_mapping'e kaydet
    // Booking.com: rooms[id]['facilities'] → [{id, name, alt_facilitytype_id, ...}]
    // View tiplerini atla (viewTypeMap ile zaten ekleniyor)
    // ─────────────────────────────────────────────────────────────────────────────
    private function mapAndSaveRoomFacilities($roomId, $propertyId, $userId, array $facilities)
    {
        // View kategorisi facilitytype_id'leri (9=View, 14=View alt) — zaten view mapping'de ekleniyor
        $skipFacilityTypeIds = array(9, 14);

        // Sistemdeki tüm fact'leri küçük harfli isimle index'e al (type=1: property/room fact)
        $allFacts   = PropertyFact::select(array('id', 'name', 'type'))->where('type', 1)->get();
        $exactIndex = array();
        foreach ($allFacts as $fact) {
            $key = mb_strtolower(trim($fact->name));
            // Aynı isimde birden fazla fact varsa daha küçük id'liyi (ilk ekleneni) tut
            if (!isset($exactIndex[$key])) {
                $exactIndex[$key] = $fact;
            }
        }

        // roomAliasMap (oda özel) + aliasMap (genel) birleştir, room öncelikli
        $combinedAlias = array_merge($this->aliasMap, $this->roomAliasMap);

        $saved   = array();
        $skipped = array();

        foreach ($facilities as $fac) {
            // View tiplerini atla
            $faciltypeId    = isset($fac['facilitytype_id'])     ? (int)$fac['facilitytype_id']     : 0;
            $altFaciltypeId = isset($fac['alt_facilitytype_id']) ? (int)$fac['alt_facilitytype_id'] : 0;
            if (in_array($faciltypeId, $skipFacilityTypeIds) || in_array($altFaciltypeId, $skipFacilityTypeIds)) {
                continue;
            }

            $name = trim(isset($fac['name']) ? $fac['name'] : '');
            if ($name === '') {
                continue;
            }

            $lower     = mb_strtolower($name);
            // Alias map'te varsa o karşılığı kullan, yoksa direkt ismi kullan
            $searchKey = isset($combinedAlias[$lower]) ? mb_strtolower($combinedAlias[$lower]) : $lower;
            $fact      = null;

            // Sadece birebir eşleşme — tahmin yok, LIKE yok
            if (isset($exactIndex[$searchKey])) {
                $fact = $exactIndex[$searchKey];
            }

            if ($fact) {
                // Yalnızca mevcut property_room_fact_mapping tablosuna yaz, yeni kayıt türü oluşturma
                $exists = DB::table('property_room_fact_mapping')
                    ->where('property_id', $propertyId)
                    ->where('room_id', $roomId)
                    ->where('fact_id', $fact->id)
                    ->exists();

                if (!$exists) {
                    DB::table('property_room_fact_mapping')->insert(array(
                        'property_id' => $propertyId,
                        'room_id'     => $roomId,
                        'fact_id'     => $fact->id,
                        'is_feature'  => 0,
                        'created_by'  => $userId,
                        'updated_by'  => $userId,
                        'created_at'  => time(),
                        'updated_at'  => time(),
                    ));
                }

                $saved[] = array(
                    'booking_name' => $name,
                    'fact_id'      => $fact->id,
                    'fact_name'    => $fact->name,
                    'via_alias'    => ($searchKey !== $lower),
                );
            } else {
                // Eşleşme yok — sisteme kesinlikle bir şey yazma, sadece logla
                Log::warning('propertyInsert.roomFacility.noMatch', array(
                    'room_id'      => $roomId,
                    'property_id'  => $propertyId,
                    'booking_name' => $name,
                    'search_key'   => $searchKey,
                    'hint'         => 'roomAliasMap veya aliasMap\'e eklenebilir',
                ));
                $skipped[] = $name;
            }
        }

        return array(
            'saved_count'   => count($saved),
            'skipped_count' => count($skipped),
            'saved'         => $saved,
            'skipped'       => $skipped,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Oda adındaki anahtar kelimelere göre room_type_id tahmin et
    // ─────────────────────────────────────────────────────────────────────────────
    private function guessRoomTypeId($roomName)
    {
        $lower = mb_strtolower($roomName);

        // Önce çift kelimeli eşleşmeleri dene (daha spesifik)
        foreach ($this->roomTypeKeywords as $keyword => $typeId) {
            if (strpos($keyword, ' ') !== false && strpos($lower, $keyword) !== false) {
                return $typeId;
            }
        }
        // Sonra tek kelimeli
        foreach ($this->roomTypeKeywords as $keyword => $typeId) {
            if (strpos($keyword, ' ') === false && strpos($lower, $keyword) !== false) {
                return $typeId;
            }
        }

        return 24; // Default: Standard Room
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ANA METOD: POST /bulut/property-insert
    // ─────────────────────────────────────────────────────────────────────────────
    public function insert(Request $request)
    {
        $hotelId      = $request->input('hotel_id', '');
        $email        = $request->input('email', '');
        $password     = $request->input('password', '');
        $name         = $request->input('name', '');
        $surname      = $request->input('surname', '');
        $propertyName = $request->input('property_name', '');
        $phone        = $request->input('phone', null);
        $dryRun       = (bool) $request->input('dry_run', false);
        $checkin      = $request->input('checkin',  date('Y-m-d', strtotime('+30 days')));
        $checkout     = $request->input('checkout', date('Y-m-d', strtotime('+31 days')));

        // Zorunlu alan validasyonu
        $required = array('hotel_id', 'email', 'password', 'name', 'surname', 'property_name');
        $missing  = array();
        foreach ($required as $field) {
            if (!$request->input($field)) {
                $missing[] = $field;
            }
        }
        if (count($missing)) {
            return response()->json(array(
                'status'  => false,
                'message' => 'Eksik alanlar: ' . implode(', ', $missing),
            ), 422);
        }

        $report = array(
            'hotel_id'      => $hotelId,
            'dry_run'       => $dryRun,
            'steps'         => array(),
        );

        try {
            DB::beginTransaction();

            // ── ADIM 0: Booking.com'dan veri çek ─────────────────────────────────
            $report['steps']['0_booking_fetch'] = array('status' => 'pending');
            $bookingData = $this->fetchBookingData($hotelId, $checkin, $checkout);
            $detail      = $bookingData['detail'];
            $facilData   = $bookingData['facilities'];
            $photoData   = $bookingData['photos'];

            $report['steps']['0_booking_fetch'] = array(
                'status'         => 'success',
                'hotel_name'     => isset($detail['hotel_name']) ? $detail['hotel_name'] : null,
                'facility_count' => $this->countFacilities($facilData),
                'photo_count'    => count($this->extractPhotoUrls($photoData)),
            );

            // Eğer property_name boş geldiyse Booking.com adını kullan
            if (!$propertyName && !empty($detail['hotel_name'])) {
                $propertyName = $detail['hotel_name'];
            }

            if ($dryRun) {
                DB::rollBack();
                $report['dry_run_note'] = 'dry_run=true → DB\'ye hiçbir şey yazılmadı. Aşağıdaki veriler oluşturulacaktı.';
                $report['steps']['1_user_property'] = array('status' => 'skipped (dry_run)', 'email' => $email, 'property_name' => $propertyName);
                $report['steps']['2_property_info']  = array('status' => 'skipped (dry_run)', 'data'  => $this->previewPropertyInfo($detail));
                $report['steps']['3_contact']         = array('status' => 'skipped (dry_run)', 'phone' => $phone ?: (isset($detail['phone']) ? $detail['phone'] : null), 'email' => isset($detail['email']) ? $detail['email'] : null);
                $report['steps']['4_fact_mapping']    = array('status' => 'skipped (dry_run)', 'facility_count' => $this->countFacilities($facilData));
                $report['steps']['5_rooms']           = array('status' => 'skipped (dry_run)');
                $report['steps']['6_photos']          = array('status' => 'skipped (dry_run)', 'photo_count' => count($this->extractPhotoUrls($photoData)));
                return response()->json(array('status' => true, 'message' => 'Dry run tamamlandı', 'report' => $report));
            }

            // ── ADIM 1: Kullanıcı + Property oluştur ────────────────────────────
            $report['steps']['1_user_property'] = array('status' => 'pending');
            $userPropertyResult = $this->createUserAndProperty(
                array('name' => $name, 'surname' => $surname, 'email' => $email, 'password' => $password),
                $propertyName
            );
            $createdUserId     = $userPropertyResult['user']['id'];
            $createdPropertyId = $userPropertyResult['property_id'];

            $report['steps']['1_user_property'] = array(
                'status'      => 'success',
                'user_id'     => $createdUserId,
                'property_id' => $createdPropertyId,
                'token'       => $userPropertyResult['token'],
            );

            // ── ADIM 2: Property info güncelle ──────────────────────────────────
            $report['steps']['2_property_info'] = array('status' => 'pending');
            $this->updatePropertyInfo($createdPropertyId, $createdUserId, $detail);
            $raw2 = isset($detail['rawData']) ? $detail['rawData'] : array();
            $report['steps']['2_property_info'] = array(
                'status'      => 'success',
                'hotel_name'  => isset($detail['hotel_name'])             ? $detail['hotel_name']               : null,
                'rating'      => isset($raw2['accuratePropertyClass'])    ? (int)$raw2['accuratePropertyClass']  : null,
                'country'     => isset($detail['countrycode'])            ? strtoupper($detail['countrycode'])   : null,
                'checkin'     => isset($raw2['checkin']['fromTime'])      ? $raw2['checkin']['fromTime']         : null,
                'checkout'    => isset($raw2['checkout']['untilTime'])    ? $raw2['checkout']['untilTime']       : null,
                'languages'   => isset($detail['spoken_languages'])       ? $detail['spoken_languages']          : array(),
            );

            // ── ADIM 3: İletişim bilgilerini kaydet ──────────────────────────────
            $report['steps']['3_contact'] = array('status' => 'pending');
            $this->updatePropertyContact($createdPropertyId, $createdUserId, $detail, $phone);
            $report['steps']['3_contact'] = array(
                'status' => 'success',
                'phone'  => $phone ?: (isset($detail['phone']) ? $detail['phone'] : null),
                'email'  => isset($detail['email']) ? $detail['email'] : null,
            );

            // ── ADIM 4: Facility → Fact mapping ─────────────────────────────────
            $report['steps']['4_fact_mapping'] = array('status' => 'pending');
            $facilityResult = $this->mapAndSaveFacilities($createdPropertyId, $createdUserId, $facilData);
            $report['steps']['4_fact_mapping'] = array_merge(array('status' => 'success'), $facilityResult);

            // ── ADIM 5: Oda ekle ─────────────────────────────────────────────────
            $report['steps']['5_rooms'] = array('status' => 'pending');
            $roomResult = $this->insertRooms($createdPropertyId, $createdUserId, $detail);
            $report['steps']['5_rooms'] = array_merge(array('status' => 'success'), $roomResult);

            // ── ADIM 6: Görselleri indir ve kaydet ───────────────────────────────
            $report['steps']['6_photos'] = array('status' => 'pending');
            $photoLimit  = $request->input('photo_limit', 20);
            $photoResult = $this->processAndSavePhotos($photoData, $hotelId, $createdPropertyId, $photoLimit);
            $report['steps']['6_photos'] = array_merge(array('status' => 'success'), $photoResult);

            DB::commit();

            return response()->json(array(
                'status'      => true,
                'message'     => 'Property başarıyla oluşturuldu',
                'property_id' => $createdPropertyId,
                'user_id'     => $createdUserId,
                'report'      => $report,
            ));
        } catch (ApiErrorException $e) {
            DB::rollBack();
            Log::error('propertyInsert.ApiError: ' . $e->getMessage());
            return response()->json(array(
                'status'  => false,
                'message' => implode(', ', $e->getMessageArr()),
                'report'  => $report,
            ), 400);
        } catch (Exception $e) {
            DB::rollBack();
            Log::error('propertyInsert.Error: ' . $e->getFile() . ':' . $e->getLine() . ' ' . $e->getMessage());
            return response()->json(array(
                'status'  => false,
                'message' => $e->getMessage(),
                'report'  => $report,
            ), 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // ADIM 6: Fotograflari indir, isle ve kaydet
    // ─────────────────────────────────────────────────────────────────────────────
    private function processAndSavePhotos(array $responseData, $hotelId, $propertyId, $limit = 20)
    {
        $photoUrls = $this->extractPhotoUrls($responseData);

        if (empty($photoUrls)) {
            return array(
                'saved_count'  => 0,
                'total_in_api' => 0,
                'message'      => 'API yanitinda fotograf URL bulunamadi',
            );
        }

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

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

        $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';

                $this->downloadRawImage($photoUrl, $tempPath);

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

                // Orijinal — 2000px uzeriyse kucult
                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);

                if (File::exists($tempPath)) {
                    File::delete($tempPath);
                }

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

                $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('propertyInsert.photo [' . $i . ']: ' . $e->getMessage() . ' | ' . $photoUrl);
                $saved[] = array('error' => $e->getMessage(), 'source_url' => $photoUrl);
            }
        }

        $okCount = count(array_filter($saved, function ($s) {
            return !isset($s['error']);
        }));

        return array(
            'saved_count'   => $okCount,
            'total_in_api'  => count($photoUrls),
            'limit_applied' => $total,
            'photos'        => $saved,
        );
    }

    private function extractPhotoUrls(array $data)
    {
        $urls = array();

        // Format 1: data[] dizisi
        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[] 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;
    }

    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);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Yardımcı: timezone string → general_timezone.id
    // ─────────────────────────────────────────────────────────────────────────────
    private function resolveTimezoneId($timezoneLocation)
    {
        $row = DB::table('general_timezone')
            ->where('location', $timezoneLocation)
            ->first();
        return $row ? (string)$row->id : null;
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Yardımcı: dry_run için property_info önizleme
    // ─────────────────────────────────────────────────────────────────────────────
    private function previewPropertyInfo(array $detail)
    {
        $raw = isset($detail['rawData']) ? $detail['rawData'] : array();
        $rating = null;
        foreach (array('accuratePropertyClass', 'propertyClass', 'qualityClass') as $rk) {
            if (!empty($raw[$rk])) {
                $rating = (int)$raw[$rk];
                break;
            }
        }
        return array(
            'name'          => isset($detail['hotel_name'])         ? $detail['hotel_name']         : null,
            'rating'        => $rating,
            'country'       => isset($detail['countrycode'])        ? strtoupper($detail['countrycode']) : null,
            'address'       => isset($detail['address'])            ? $detail['address']            : null,
            'city'          => isset($detail['city_name_en'])       ? $detail['city_name_en']       : null,
            'district'      => isset($detail['district'])           ? $detail['district']           : null,
            'zip'           => isset($detail['zip'])                ? $detail['zip']                : null,
            'latitude'      => isset($detail['latitude'])           ? $detail['latitude']           : null,
            'longitude'     => isset($detail['longitude'])          ? $detail['longitude']          : null,
            'timezone'      => isset($detail['timezone'])           ? $detail['timezone']           : null,
            'checkin'       => isset($raw['checkin']['fromTime'])   ? $raw['checkin']['fromTime']   : null,
            'checkout'      => isset($raw['checkout']['untilTime']) ? $raw['checkout']['untilTime'] : null,
            'languages'     => isset($detail['spoken_languages'])   ? $detail['spoken_languages']   : array(),
            'review_score'  => isset($raw['reviewScore'])           ? $raw['reviewScore']           : null,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // Yardımcı: facility sayısını döndür
    // ─────────────────────────────────────────────────────────────────────────────
    private function countFacilities(array $facilData)
    {
        $count = 0;
        if (isset($facilData['facilities'])) {
            foreach ($facilData['facilities'] as $fac) {
                $count += count(isset($fac['instances']) ? $fac['instances'] : array());
            }
        }
        return $count;
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // GET /bulut/property-check?email=...
    // Verilen email'e ait kullanıcı ve property bilgilerini döndür
    // ─────────────────────────────────────────────────────────────────────────────
    public function check(Request $request)
    {
        $email = trim($request->input('email', ''));
        if (!$email) {
            return response()->json(array('status' => false, 'message' => 'email parametresi gerekli'), 422);
        }

        $user = DB::table('user')->where('email', $email)->first();
        if (!$user) {
            return response()->json(array(
                'status'  => false,
                'message' => 'Kullanıcı bulunamadı',
                'email'   => $email,
            ));
        }

        // Kullanıcıya bağlı property'ler
        $mappings = DB::table('user_property_mapping as upm')
            ->join('property as p', 'p.id', '=', 'upm.property_id')
            ->where('upm.user_id', $user->id)
            ->select(array(
                'p.id as property_id',
                'p.name as property_name',
                'p.status as property_status',
                'upm.created_at',
            ))
            ->get();

        $properties = array();
        foreach ($mappings as $m) {
            $roomCount  = DB::table('property_room')->where('property_id', $m->property_id)->count();
            $photoCount = DB::table('property_photo')->where('property_id', $m->property_id)->count();
            $factCount  = DB::table('property_fact_mapping')->where('property_id', $m->property_id)->count();

            $properties[] = array(
                'property_id'   => $m->property_id,
                'property_name' => $m->property_name,
                'status'        => $m->property_status,
                'room_count'    => $roomCount,
                'photo_count'   => $photoCount,
                'fact_count'    => $factCount,
                'created_at'    => date('Y-m-d H:i:s', $m->created_at),
            );
        }

        return response()->json(array(
            'status'     => true,
            'user_id'    => $user->id,
            'email'      => $user->email,
            'name'       => $user->name . ' ' . $user->surname,
            'user_status' => $user->status,
            'properties' => $properties,
        ));
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // DELETE /bulut/property-delete
    // Body: { "property_id": 123 }  veya  { "email": "..." }  (emailde tüm property'ler)
    // Odalar, fotoğraflar (dosya dahil), fact mapping, iletişim, user-property mapping,
    // property kaydı ve kullanıcı silinir.
    // ─────────────────────────────────────────────────────────────────────────────
    public function delete(Request $request)
    {
        $propertyId = $request->input('property_id');
        $email      = trim($request->input('email', ''));

        if (!$propertyId && !$email) {
            return response()->json(array('status' => false, 'message' => 'property_id veya email gerekli'), 422);
        }

        $report = array();

        try {
            DB::beginTransaction();

            // Email ile geldiyse önce kullanıcı + property_id'leri bul
            $userIdToDelete = null;
            $propertyIds    = array();

            if ($email) {
                $user = DB::table('user')->where('email', $email)->first();
                if (!$user) {
                    return response()->json(array('status' => false, 'message' => 'Kullanıcı bulunamadı'));
                }
                $userIdToDelete = $user->id;
                $pids = DB::table('user_property_mapping')
                    ->where('user_id', $userIdToDelete)
                    ->pluck('property_id')
                    ->toArray();
                $propertyIds = $pids;
            } else {
                $propertyIds = array((int)$propertyId);
                // Bu property'nin tek sahibi varsa onu da sil
                $ownerCount = DB::table('user_property_mapping')
                    ->where('property_id', $propertyId)
                    ->count();
                if ($ownerCount === 1) {
                    $userIdToDelete = DB::table('user_property_mapping')
                        ->where('property_id', $propertyId)
                        ->value('user_id');
                }
            }

            foreach ($propertyIds as $pid) {
                $deleted = array('property_id' => $pid);

                // 1. Fotoğraf dosyalarını sil
                $photos = DB::table('property_photo')->where('property_id', $pid)->get();
                $filesDeleted = 0;
                $uploadRoot = rtrim(Config::get('app.fileSystemDriver'), '/');
                foreach ($photos as $photo) {
                    $base = $uploadRoot . $photo->photo_path . $photo->photo_name;
                    foreach (array('', '_medium', '_thumbnail') as $suffix) {
                        $path = $base . $suffix . '.' . $photo->file_ext;
                        if (File::exists($path)) {
                            File::delete($path);
                            $filesDeleted++;
                        }
                    }
                }
                $deleted['photos_db']   = DB::table('property_photo')->where('property_id', $pid)->delete();
                $deleted['photos_files'] = $filesDeleted;

                // 2. Oda ilişkileri
                $roomIds = DB::table('property_room')->where('property_id', $pid)->pluck('id')->toArray();
                if (!empty($roomIds)) {
                    DB::table('property_room_bed')->whereIn('room_id', $roomIds)->delete();
                    DB::table('property_room_view_mapping')->whereIn('room_id', $roomIds)->delete();
                    DB::table('property_room_fact_mapping')->whereIn('room_id', $roomIds)->delete();
                    DB::table('property_room_photo_mapping')->whereIn('room_id', $roomIds)->delete();
                }
                $deleted['rooms'] = DB::table('property_room')->where('property_id', $pid)->delete();

                // 3. Fact mapping
                $deleted['fact_mapping'] = DB::table('property_fact_mapping')->where('property_id', $pid)->delete();

                // 4. İletişim
                $deleted['contact'] = DB::table('property_contact')->where('property_id', $pid)->delete();

                // 5. Property info tabloları
                DB::table('property_additional_info')->where('property_id', $pid)->delete();
                DB::table('property_language_spoken')->where('property_id', $pid)->delete();

                // 6. User-property mapping
                $deleted['user_mapping'] = DB::table('user_property_mapping')->where('property_id', $pid)->delete();

                // 7. Property kaydı
                $deleted['property'] = DB::table('property')->where('id', $pid)->delete();

                $report[] = $deleted;
            }

            // 8. Kullanıcıyı sil (başka property'si yoksa)
            if ($userIdToDelete) {
                $remaining = DB::table('user_property_mapping')->where('user_id', $userIdToDelete)->count();
                if ($remaining === 0) {
                    DB::table('api_access_token')->where('user_id', $userIdToDelete)->delete();
                    DB::table('user')->where('id', $userIdToDelete)->delete();
                    $report['user_deleted'] = $userIdToDelete;
                }
            }

            DB::commit();

            return response()->json(array(
                'status'  => true,
                'message' => 'Silme tamamlandı',
                'report'  => $report,
            ));
        } catch (Exception $e) {
            DB::rollBack();
            Log::error('propertyDelete.Error: ' . $e->getFile() . ':' . $e->getLine() . ' ' . $e->getMessage());
            return response()->json(array(
                'status'  => false,
                'message' => $e->getMessage(),
                'report'  => $report,
            ), 500);
        }
    }
}
