<?php
@ini_set('display_errors','0'); @ini_set('log_errors','1');
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/../includes/mj_v3041_access_notifications_location.php';
header('Content-Type: application/json; charset=utf-8');
function mj427_loc_out(array $data): void { echo json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); exit; }
function mj427_loc_slug(string $s): string { return function_exists('mjv3041_slug') ? mjv3041_slug($s) : strtolower(trim(preg_replace('/[^a-z0-9]+/i','-', $s), '-')); }
function mj427_loc_ensure_schema(): void {
    try { mjv3041_ensure_light_schema(); } catch (Throwable $e) {}
    try { q("CREATE TABLE IF NOT EXISTS mj_location_cache (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        cache_key CHAR(64) NOT NULL UNIQUE,
        cache_type VARCHAR(40) NOT NULL,
        query_text VARCHAR(180) NULL,
        country_id INT NULL,
        state_id BIGINT NULL,
        result_json LONGTEXT NULL,
        hit_count INT NOT NULL DEFAULT 0,
        expires_at DATETIME NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT NULL,
        INDEX idx_type_query(cache_type, query_text), INDEX idx_country_state(country_id,state_id), INDEX idx_expires(expires_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}
    try { q("ALTER TABLE mj_countries ADD INDEX IF NOT EXISTS idx_mj427_country_search (is_active, name, iso2)"); } catch (Throwable $e) {}
    try { q("ALTER TABLE mj_states ADD INDEX IF NOT EXISTS idx_mj427_state_search (country_id, is_active, name)"); } catch (Throwable $e) {}
    try { q("ALTER TABLE mj_cities ADD INDEX IF NOT EXISTS idx_mj427_city_search (country_id, state_id, is_active, name)"); } catch (Throwable $e) {}
}
function mj427_cache_get(string $type, string $q, int $countryId=0, int $stateId=0): ?array {
    try {
        $key = hash('sha256', strtolower($type.'|'.$q.'|'.$countryId.'|'.$stateId));
        $r = one('SELECT result_json FROM mj_location_cache WHERE cache_key=? AND (expires_at IS NULL OR expires_at>NOW()) LIMIT 1', [$key]);
        if ($r && !empty($r['result_json'])) { q('UPDATE mj_location_cache SET hit_count=hit_count+1 WHERE cache_key=?', [$key]); $j=json_decode((string)$r['result_json'], true); return is_array($j)?$j:null; }
    } catch (Throwable $e) {}
    return null;
}
function mj427_cache_set(string $type, string $q, int $countryId, int $stateId, array $data, int $ttlSeconds=3600): void {
    try {
        $key = hash('sha256', strtolower($type.'|'.$q.'|'.$countryId.'|'.$stateId));
        q('INSERT INTO mj_location_cache(cache_key,cache_type,query_text,country_id,state_id,result_json,expires_at,created_at,updated_at) VALUES(?,?,?,?,?,?,DATE_ADD(NOW(), INTERVAL ? SECOND),NOW(),NOW()) ON DUPLICATE KEY UPDATE result_json=VALUES(result_json),expires_at=VALUES(expires_at),updated_at=NOW()', [$key,$type,mb_substr($q,0,180),$countryId?:null,$stateId?:null,json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),$ttlSeconds]);
    } catch (Throwable $e) {}
}
function mj427_fetch_open_meteo(string $q, string $iso2=''): array {
    if (mb_strlen($q) < 2) return [];
    $url = 'https://geocoding-api.open-meteo.com/v1/search?count=8&language=en&format=json&name='.rawurlencode($q);
    if ($iso2 && preg_match('/^[A-Z]{2}$/', strtoupper($iso2))) $url .= '&countryCode='.strtoupper($iso2);
    $ctx = stream_context_create(['http'=>['timeout'=>2, 'ignore_errors'=>true, 'header'=>"User-Agent: MJMarketplace/3.0.4.2.7\r\n"]]);
    $raw = @file_get_contents($url, false, $ctx); if (!$raw) return [];
    $json = json_decode($raw, true); return is_array($json['results'] ?? null) ? $json['results'] : [];
}
function mj427_popular_cities(int $countryId=0): array {
    $popular = ['Singapore','Kuala Lumpur','Johor Bahru','Bangkok','Jakarta','Manila','Dubai','London','New York','Sydney','Mumbai','Delhi','Chennai'];
    $rows=[];
    try {
        $where = 'is_active=1'; $params=[];
        if ($countryId>0) { $where .= ' AND country_id=?'; $params[]=$countryId; }
        $in = implode(',', array_fill(0, count($popular), '?'));
        $rows = all_rows("SELECT id,name,timezone,latitude,longitude FROM mj_cities WHERE $where AND name IN ($in) ORDER BY FIELD(name,$in) LIMIT 15", array_merge($params,$popular,$popular));
    } catch (Throwable $e) {}
    $out=[]; foreach($rows as $r){ $out[]=['id'=>(string)$r['id'],'text'=>$r['name'],'name'=>$r['name'],'local'=>true,'popular'=>true,'timezone'=>$r['timezone']??'','lat'=>$r['latitude']??null,'lng'=>$r['longitude']??null]; }
    return $out;
}
try {
    mj427_loc_ensure_schema();
    $action = strtolower(trim((string)($_REQUEST['action'] ?? 'countries')));
    $qv = trim((string)($_REQUEST['q'] ?? $_REQUEST['term'] ?? ''));
    $limit = min(30, max(5, (int)($_REQUEST['limit'] ?? 15)));
    $countryId = (int)($_REQUEST['country_id'] ?? 0); $stateId = (int)($_REQUEST['state_id'] ?? 0);

    if (in_array($action, ['countries','states','cities'], true)) {
        $cached = mj427_cache_get($action, $qv, $countryId, $stateId);
        if ($cached !== null) mj427_loc_out(['ok'=>true,'results'=>array_slice($cached,0,$limit),'cached'=>true]);
    }

    if ($action === 'countries') {
        $params=[]; $where='is_active=1';
        if ($qv !== '') { $where .= ' AND (name LIKE ? OR iso2 LIKE ? OR iso3 LIKE ?)'; $params[]='%'.$qv.'%'; $params[]=$qv.'%'; $params[]=$qv.'%'; }
        $rows = all_rows("SELECT id,name,iso2,iso3,flag_emoji,currency_code,timezone_default,phone_code FROM mj_countries WHERE $where ORDER BY sort_order DESC, name LIMIT $limit", $params);
        $out=[]; foreach($rows as $r){ $out[]=['id'=>(string)$r['id'],'text'=>trim(($r['flag_emoji']??'').' '.$r['name']),'name'=>$r['name'],'iso2'=>$r['iso2']??'','iso3'=>$r['iso3']??'','currency'=>$r['currency_code']??'','timezone'=>$r['timezone_default']??'','phone_code'=>$r['phone_code']??'']; }
        mj427_cache_set($action,$qv,0,0,$out,86400); mj427_loc_out(['ok'=>true,'results'=>$out]);
    }
    if ($action === 'states') {
        if ($countryId<=0) mj427_loc_out(['ok'=>true,'results'=>[],'message'=>'Select country first']);
        $params=[$countryId]; $where='country_id=? AND is_active=1';
        if ($qv !== '') { $where .= ' AND (name LIKE ? OR state_code LIKE ? OR slug LIKE ?)'; $params[]='%'.$qv.'%'; $params[]=$qv.'%'; $params[]=mj427_loc_slug($qv).'%'; }
        $rows = all_rows("SELECT id,name,state_code,timezone FROM mj_states WHERE $where ORDER BY name LIMIT $limit", $params);
        $out=[]; foreach($rows as $r){ $out[]=['id'=>(string)$r['id'],'text'=>$r['name'].(!empty($r['state_code'])?' ('.$r['state_code'].')':''),'name'=>$r['name'],'timezone'=>$r['timezone']??'']; }
        if (!$out && mb_strlen($qv)>=2) $out[]=['id'=>'manual_state:'.base64_encode($qv),'text'=>'Add state/area: '.$qv,'manual'=>true,'name'=>$qv];
        mj427_cache_set($action,$qv,$countryId,0,$out,86400); mj427_loc_out(['ok'=>true,'results'=>$out]);
    }
    if ($action === 'cities') {
        if ($qv === '' || mb_strlen($qv) < 2) { $out = mj427_popular_cities($countryId); mj427_loc_out(['ok'=>true,'results'=>array_slice($out,0,$limit),'hint'=>'Type at least 2 letters to search city']); }
        $params=[]; $where='is_active=1';
        if ($countryId>0) { $where.=' AND country_id=?'; $params[]=$countryId; }
        if ($stateId>0) { $where.=' AND state_id=?'; $params[]=$stateId; }
        $where .= ' AND (name LIKE ? OR slug LIKE ?)'; $params[]=$qv.'%'; $params[]=mj427_loc_slug($qv).'%';
        $rows = all_rows("SELECT id,name,timezone,latitude,longitude FROM mj_cities WHERE $where ORDER BY name LIMIT $limit", $params);
        $out=[]; foreach($rows as $r){ $out[]=['id'=>(string)$r['id'],'text'=>$r['name'],'name'=>$r['name'],'local'=>true,'timezone'=>$r['timezone']??'','lat'=>$r['latitude']??null,'lng'=>$r['longitude']??null]; }
        if (count($out)<5) {
            $country = $countryId ? one('SELECT iso2,name FROM mj_countries WHERE id=? LIMIT 1', [$countryId]) : null;
            foreach (mj427_fetch_open_meteo($qv, (string)($country['iso2'] ?? '')) as $r) {
                $payload=['name'=>(string)($r['name']??''),'country'=>(string)($r['country']??''),'country_code'=>(string)($r['country_code']??''),'state'=>(string)($r['admin1']??''),'state_code'=>(string)($r['admin1_id']??''),'lat'=>$r['latitude']??null,'lng'=>$r['longitude']??null,'timezone'=>(string)($r['timezone']??'')];
                if ($payload['name']==='') continue; $label=$payload['name']; if($payload['state'])$label.=', '.$payload['state']; if($payload['country'])$label.=', '.$payload['country'];
                $out[]=['id'=>'live:'.base64_encode(json_encode($payload,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)),'text'=>$label,'name'=>$payload['name'],'live'=>true,'payload'=>$payload];
            }
        }
        $out[]=['id'=>'manual_city:'.base64_encode($qv),'text'=>'Add city manually: '.$qv,'manual'=>true,'name'=>$qv];
        $out = array_slice($out,0,$limit); mj427_cache_set($action,$qv,$countryId,$stateId,$out,3600); mj427_loc_out(['ok'=>true,'results'=>$out]);
    }
    if ($action === 'save_live_city' || $action === 'save_manual_city') {
        $payload=[]; if(!empty($_POST['payload'])) $payload=json_decode((string)$_POST['payload'], true) ?: [];
        $cityName=trim((string)($_POST['city_name'] ?? ($payload['name'] ?? ''))); if($cityName==='') throw new RuntimeException('City name required.');
        if ($countryId<=0) $countryId=mjv3041_ensure_country((string)($payload['country']??''),(string)($payload['country_code']??''),(string)($payload['timezone']??''),'');
        if ($stateId<=0 && !empty($payload['state']) && $countryId>0) $stateId=mjv3041_ensure_state($countryId,(string)$payload['state'],(string)($payload['state_code']??''),(string)($payload['timezone']??''));
        $cityId=mjv3041_ensure_city($countryId,$stateId?:null,$cityName,isset($payload['lat'])?(float)$payload['lat']:null,isset($payload['lng'])?(float)$payload['lng']:null,(string)($payload['timezone']??''),$action==='save_manual_city'?'manual':'live');
        mj427_loc_out(['ok'=>true,'country_id'=>$countryId,'state_id'=>$stateId,'city_id'=>$cityId,'city_name'=>$cityName]);
    }
    mj427_loc_out(['ok'=>false,'error'=>'Unknown action']);
} catch (Throwable $e) { mj427_loc_out(['ok'=>false,'error'=>$e->getMessage()]); }
