import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../config/app_config.dart'; import '../models/landmark.dart'; class LandmarkDatabase { static const String _storageKey = 'cached_tactical_landmarks_v1'; static List _dynamicLandmarks = []; static bool _isLoaded = false; static final List _builtInLandmarks = const [ // ── Amman Region (العاصمة عمان) ─────────────────────────── TacticalLandmark( id: 'amm-1', name: 'مئذنة مسجد الملك حسين (دابوق)', region: 'عمان الغربية', type: LandmarkType.minaret, lat: 31.9835, lng: 35.8285, elevationM: 1010, description: 'مئذنة حجرية بارزة ترى بوضوح من غرب وشمال العاصمة وشارع الأردن', ), TacticalLandmark( id: 'amm-2', name: 'برج اتصالات جبل التاج / جبل القلعة', region: 'وسط عمان', type: LandmarkType.tower, lat: 31.9540, lng: 35.9350, elevationM: 850, description: 'برج إرسال رئيسي مرتفع يشرف على وسط البلد وشرق عمان', ), TacticalLandmark( id: 'amm-3', name: 'خزان مياه دابوق العالي (البرج الدائري)', region: 'عمان الغربية', type: LandmarkType.waterTank, lat: 31.9960, lng: 35.8150, elevationM: 1045, description: 'خزان خرساني ضخم على أعلى تلة في دابوق', ), TacticalLandmark( id: 'amm-4', name: 'برج اتصالات صويلح (الدوريات الخارجية)', region: 'شمال عمان', type: LandmarkType.tower, lat: 32.0250, lng: 35.8450, elevationM: 1070, description: 'أعلى نقطة رصد شمال غرب العاصمة على تقاطع طريق الشمال', ), TacticalLandmark( id: 'amm-5', name: 'مئذنة مسجد الملك المؤسس عبدالله الأول (العبدلي)', region: 'وسط عمان', type: LandmarkType.minaret, lat: 31.9615, lng: 35.9130, elevationM: 880, description: 'قبة زرقاء شهيرة ومئذنتان واضحتان في قلب العبدلي', ), TacticalLandmark( id: 'amm-6', name: 'أبراج بوابة الأردن (أبراج الدوار السادس)', region: 'عمان الغربية', type: LandmarkType.tower, lat: 31.9580, lng: 35.8680, elevationM: 990, description: 'برجان توأم زجاجيان عاليان يشاهدان من جميع أطراف العاصمة', ), TacticalLandmark( id: 'amm-7', name: 'صوامع حبوب الجيزة / المطار', region: 'جنوب عمان', type: LandmarkType.grainSilo, lat: 31.6980, lng: 35.9520, elevationM: 730, description: 'منشأة صوامع خرسانية عالية على الطريق الصحراوي الرئيسي', ), TacticalLandmark( id: 'amm-8', name: 'خزان مياه طبربور / عين غزال', region: 'شمال شرق عمان', type: LandmarkType.waterTank, lat: 31.9890, lng: 35.9420, elevationM: 820, description: 'برج مياه تكتيكي يشرف على اتوستراد عمان الزرقاء', ), // ── Zarqa & Desert Corridor (الزرقاء والبادية) ───────────── TacticalLandmark( id: 'zrq-1', name: 'مئذنة مسجد الشهيد راشد الزيود (غريسا)', region: 'الزرقاء', type: LandmarkType.minaret, lat: 32.0910, lng: 36.0950, elevationM: 610, description: 'مئذنة عالية تشرف على سهول الهاشمية وقرى الزرقاء', ), TacticalLandmark( id: 'zrq-2', name: 'قاعدة الشهيد موفق السلطي الجوية (الأزرق)', region: 'الأزرق / الصحراء الشرقية', type: LandmarkType.militaryBase, lat: 31.8320, lng: 36.7860, elevationM: 520, description: 'قاعدة جوية رئيسية ومعلم عسكري إستراتيجي في البادية الشرقية', ), TacticalLandmark( id: 'zrq-3', name: 'قلعة الأزرق التاريخية (قلعة البازلت)', region: 'الأزرق', type: LandmarkType.fort, lat: 31.8800, lng: 36.8270, elevationM: 505, description: 'حصن أثري من الحجر البازلتي الأسود يشرف على واحة الأزرق', ), // ── North Region (إربد، عجلون، جرش، المفرق) ──────────────── TacticalLandmark( id: 'irb-1', name: 'برج اتصالات جامعة اليرموك (إربد)', region: 'إربد', type: LandmarkType.tower, lat: 32.5340, lng: 35.8540, elevationM: 580, description: 'برج إرسال رئيسي يشرف على كامل قاطع محافظة إربد وسهول حوران', ), TacticalLandmark( id: 'irb-2', name: 'مئذنة مسجد إربد الكبير', region: 'وسط إربد', type: LandmarkType.minaret, lat: 32.5560, lng: 35.8490, elevationM: 590, description: 'مئذنة تاريخية مميزة في مركز المدينة القديمة', ), TacticalLandmark( id: 'ajl-1', name: 'قلعة عجلون (قلعة الربض)', region: 'عجلون', type: LandmarkType.fort, lat: 32.3250, lng: 35.7270, elevationM: 1020, description: 'أعلى قمة عسكرية تاريخية تشرف على جبال الشمال وغور الأردن', ), TacticalLandmark( id: 'jrs-1', name: 'أعمدة معبد أرتميس (جرش الأثرية)', region: 'جرش', type: LandmarkType.fort, lat: 32.2815, lng: 35.8910, elevationM: 600, description: 'أعمدة أثرية ضخمة ترى بوضوح من تلال جرش المقابلة', ), TacticalLandmark( id: 'mfq-1', name: 'قاعدة الملك حسين الجوية (المفرق)', region: 'المفرق', type: LandmarkType.militaryBase, lat: 32.3560, lng: 36.2590, elevationM: 680, description: 'منشأة ومدرج طيران رئيسي في سهول الشمال الشرقي', ), // ── Balqa & Salt (البلقاء والسلط والبحر الميت) ───────────── TacticalLandmark( id: 'slt-1', name: 'مئذنة مسجد السلط الكبير', region: 'السلط', type: LandmarkType.minaret, lat: 32.0390, lng: 35.7280, elevationM: 790, description: 'مئذنة في وسط السلط تشرف على سفوح جبال البلقاء', ), TacticalLandmark( id: 'slt-2', name: 'قمة جبل نيبو (النبي موسى - مادبا)', region: 'مادبا / البلقاء', type: LandmarkType.mountain, lat: 31.7680, lng: 35.7250, elevationM: 810, description: 'مطل استراتيجي مرتفع يطل على وادي الأردن والبحر الميت والقدس', ), TacticalLandmark( id: 'dms-1', name: 'نقطة المراقبة البحرية (شمال البحر الميت)', region: 'البحر الميت', type: LandmarkType.militaryBase, lat: 31.7200, lng: 35.5800, elevationM: -390, description: 'برج مراقبة على الشاطئ الشمالي لأخفض نقطة على سطح الأرض', ), // ── South Region (الكرك، الطفيلة، معان، العقبة) ─────────── TacticalLandmark( id: 'krk-1', name: 'قلعة الكرك التاريخية (برج الحصن)', region: 'الكرك', type: LandmarkType.fort, lat: 31.1810, lng: 35.7020, elevationM: 950, description: 'حصن صخري منيع يشرف على كامل قاطع الكرك والوديان الغربية', ), TacticalLandmark( id: 'taf-1', name: 'برج اتصالات جبل العيص (الطفيلة)', region: 'الطفيلة', type: LandmarkType.tower, lat: 30.8420, lng: 35.6180, elevationM: 1250, description: 'أعلى قمة في قاطع الطفيلة عليها أبراج رادار واتصالات', ), TacticalLandmark( id: 'man-1', name: 'قلعة الشوبك (مونتريال)', region: 'معان / الشوبك', type: LandmarkType.fort, lat: 30.5315, lng: 35.5610, elevationM: 1330, description: 'قلعة مخروطية عالية فوق تلة منعزلة ترى من مسافات بعيدة', ), TacticalLandmark( id: 'aqb-1', name: 'سارية علم الثورة العربية الكبرى (ساحل العقبة)', region: 'العقبة', type: LandmarkType.tower, lat: 29.5215, lng: 35.0015, elevationM: 135, description: 'سارية علم بطول 130 متراً تشاهد من كامل خليج العقبة والحدود', ), TacticalLandmark( id: 'aqb-2', name: 'صوامع ميناء العقبة الجنوبي', region: 'العقبة', type: LandmarkType.grainSilo, lat: 29.4120, lng: 34.9810, elevationM: 25, description: 'صوامع ومنشآت تخزين عملاقة على الساحل الجنوبي', ), ]; static List get allLandmarks { if (_dynamicLandmarks.isEmpty) { return _builtInLandmarks; } // Merge dynamic with built-in by unique ID final map = {}; for (final lm in _builtInLandmarks) { map[lm.id] = lm; } for (final lm in _dynamicLandmarks) { map[lm.id] = lm; } return map.values.toList(); } /// Initialize local cache from persistent storage (permanent documents directory) static Future initCache() async { if (_isLoaded) return; try { // 1. Try reading from permanent application documents file final dir = await getApplicationDocumentsDirectory(); final dbFile = File('${dir.path}/jordan_tactical_landmarks.json'); if (await dbFile.exists()) { final rawJson = await dbFile.readAsString(); if (rawJson.isNotEmpty) { final List list = jsonDecode(rawJson); _dynamicLandmarks = list.map((item) => _parseLandmark(item)).toList(); _isLoaded = true; return; } } // 2. Fallback to SharedPreferences final prefs = await SharedPreferences.getInstance(); final rawJson = prefs.getString(_storageKey); if (rawJson != null && rawJson.isNotEmpty) { final List list = jsonDecode(rawJson); _dynamicLandmarks = list.map((item) => _parseLandmark(item)).toList(); } _isLoaded = true; } catch (e) { debugPrint('Landmark cache init error: $e'); } } /// Sync landmarks from Server API and update local permanent storage static Future syncFromServer({ String? serverUrl, String? apiKey, }) async { final activeUrl = serverUrl ?? AppConfig.serverUrl; final activeKey = apiKey ?? AppConfig.apiKey; try { final url = Uri.parse('$activeUrl/api/tactical/landmarks'); final resp = await http.get(url, headers: {'x-api-key': activeKey}).timeout(const Duration(seconds: 10)); if (resp.statusCode == 200) { final data = jsonDecode(resp.body); if (data['landmarks'] != null && data['landmarks'] is List) { final List rawList = data['landmarks']; _dynamicLandmarks = rawList.map((item) => _parseLandmark(item)).toList(); // Save to permanent documents directory try { final dir = await getApplicationDocumentsDirectory(); final dbFile = File('${dir.path}/jordan_tactical_landmarks.json'); await dbFile.writeAsString(jsonEncode(rawList)); } catch (fileErr) { debugPrint('Error writing landmarks file: $fileErr'); } final prefs = await SharedPreferences.getInstance(); await prefs.setString(_storageKey, jsonEncode(rawList)); return _dynamicLandmarks.length; } } } catch (e) { debugPrint('Sync landmarks error: $e'); } return _dynamicLandmarks.length; } static TacticalLandmark _parseLandmark(dynamic json) { LandmarkType parseType(String? t) { switch (t) { case 'minaret': return LandmarkType.minaret; case 'tower': return LandmarkType.tower; case 'waterTank': return LandmarkType.waterTank; case 'fort': return LandmarkType.fort; case 'mountain': return LandmarkType.mountain; case 'militaryBase': return LandmarkType.militaryBase; case 'grainSilo': return LandmarkType.grainSilo; default: return LandmarkType.tower; } } return TacticalLandmark( id: json['id'] ?? 'lm-${DateTime.now().millisecondsSinceEpoch}', name: json['name'] ?? 'معلم تكتيكي', region: json['region'] ?? 'الأردن', type: parseType(json['type']), lat: (json['lat'] as num).toDouble(), lng: (json['lng'] as num).toDouble(), elevationM: (json['elevationM'] as num?)?.toInt() ?? 800, description: json['description'] ?? '', ); } static List search(String query, {String? region, LandmarkType? type}) { final cleanQuery = query.trim().toLowerCase(); return allLandmarks.where((landmark) { if (region != null && region.isNotEmpty && region != 'الكل') { if (!landmark.region.contains(region)) return false; } if (type != null) { if (landmark.type != type) return false; } if (cleanQuery.isEmpty) return true; return landmark.name.toLowerCase().contains(cleanQuery) || landmark.region.toLowerCase().contains(cleanQuery) || landmark.description.toLowerCase().contains(cleanQuery) || landmark.typeLabelArabic.contains(cleanQuery); }).toList(); } }