import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:geolocator/geolocator.dart';
import 'package:siro_rider/constant/api_key.dart';
import 'package:siro_rider/controller/firebase/firbase_messge.dart';
import 'package:siro_rider/views/auth/otp_page.dart';
import 'package:siro_rider/views/widgets/error_snakbar.dart';
import 'package:http/http.dart' as http;

import 'package:siro_rider/constant/info.dart';
import 'package:siro_rider/controller/functions/add_error.dart';
import 'package:siro_rider/views/auth/login_page.dart';

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_rider/constant/box_name.dart';
import 'package:siro_rider/constant/links.dart';
import 'package:siro_rider/controller/functions/crud.dart';
import 'package:siro_rider/main.dart';
import 'package:siro_rider/views/home/map_page_passenger.dart';

import 'package:location/location.dart';

import '../../env/env.dart';
import '../../print.dart';
import '../../views/auth/otp_token_page.dart';
import '../functions/country_logic.dart';
import '../functions/encrypt_decrypt.dart';
import '../functions/package_info.dart';

class LoginController extends GetxController {
  final formKey = GlobalKey<FormState>();
  final formKeyAdmin = GlobalKey<FormState>();
  TextEditingController emailController = TextEditingController();
  TextEditingController phoneController = TextEditingController();
  TextEditingController passwordController = TextEditingController();
  TextEditingController adminPasswordController = TextEditingController();
  TextEditingController adminNameController = TextEditingController();
  bool isAgreeTerms = false;
  bool isloading = false;
  late int isTest = 1;
  void changeAgreeTerm() {
    isAgreeTerms = !isAgreeTerms;
    update();
  }

  var dev = '';
  @override
  void onInit() async {
    // Log.print('box.read(BoxName.isTest): ${box.read(BoxName.isTest)}');
    // كشف الدولة تلقائياً عبر الموقع الجغرافي
    await CountryLogic.initializeCountry();
    FirebaseMessagesController().getToken();
    super.onInit();
  }

  void saveAgreementTerms() {
    box.write(BoxName.agreeTerms, 'agreed');
    update();
  }

  void saveCountryCode(String countryCode) {
    box.write(BoxName.countryCode, countryCode);
    update();
  }

  // ═══════════════════════════════════════════════════════════════
// LoginController — دوال إدارة الـ JWT
// ───────────────────────────────────────────────────────────────
// لا تغيير على اسم الكلاس أو أسماء الدوال
// ═══════════════════════════════════════════════════════════════

// داخل class LoginController

  // ─────────────────────────────────────────────────────────────
  // getJWT: الحصول على توكن للراكب
  // ─────────────────────────────────────────────────────────────
  // المنطق:
  //   • firstTimeLoadKey != false  ← أول مرة يفتح التطبيق → loginFirstTime
  //   • firstTimeLoadKey == false  ← مستخدم موجود         → loginJwtRider
  // ─────────────────────────────────────────────────────────────
  Future<void> getJWT() async {
    // إذا كان التوكن الحالي لا يزال صالحاً، لا داعي لطلب واحد جديد
    if (isTokenValid()) {
      Log.print("JWT is still valid. Skipping request.");
      return;
    }

    try {
      dev = Platform.isAndroid ? 'android' : 'ios';

      // تأكد إن البصمة محدّثة قبل أي طلب
      await DeviceHelper.getDeviceFingerprint();
      final String fp = box.read(BoxName.deviceFpEncrypted) ?? '';

      if (box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
        // ── أول تسجيل ─────────────────────────────────────────
        // نرسل البصمة المشفرة مع باقي البيانات
        // السيرفر سيعمل hash لها ويخزنها في JWT payload
        var payload = {
          'id': box.read(BoxName.passengerID) ?? AK.newId,
          'password': AK.passnpassenger,
          'aud': '${AK.allowed}$dev',
          'fingerPrint': fp,
        };

        var response = await http.post(
          Uri.parse(AppLink.loginFirstTime),
          body: payload,
        );
        Log.print('AppLink.loginFirstTime: ${AppLink.loginFirstTime}');

        Log.print('payload: $payload');
        Log.print('response: $response');

        if (response.statusCode == 200) {
          final decoded = jsonDecode(response.body);
          final String? jwt = decoded['data'] != null
              ? decoded['data']['jwt']
              : (decoded['message'] != null
                  ? decoded['message']['jwt']
                  : decoded['jwt']);

          if (jwt != null) {
            // نشفر الـ JWT بالتشفير الثلاثي قبل التخزين في GetStorage
            box.write(BoxName.jwt, c(jwt));
          }

          await EncryptionHelper.initialize();
        }
      } else {
        // ── مستخدم موجود: تجديد التوكن ────────────────────────
        await EncryptionHelper.initialize();

        var payload = {
          'id': box.read(BoxName.passengerID),
          'fingerPrint': fp,
          'aud': '${AK.allowed}$dev',
        };

        var response = await http.post(
          Uri.parse(AppLink.loginJwtRider),
          body: payload,
        );
        Log.print('AppLink.loginJwtRider: ${AppLink.loginJwtRider}');

        Log.print('payload: $payload');
        Log.print('response: ${response.body}');
        if (response.statusCode == 200) {
          final decoded = jsonDecode(response.body);
          final String? jwt = decoded['data'] != null
              ? decoded['data']['jwt']
              : (decoded['message'] != null
                  ? decoded['message']['jwt']
                  : decoded['jwt']);

          if (jwt != null) {
            box.write(BoxName.jwt, c(jwt));
          }
        }
      }
    } catch (e) {
      Log.print('Error in getJWT: $e');
    }
  }

  // ─────────────────────────────────────────────────────────────
  // التحقق من صلاحية التوكن يدوياً (بدون مكاتب خارجية)
  // ─────────────────────────────────────────────────────────────
  bool isTokenValid() {
    try {
      final String? encryptedJwt = box.read(BoxName.jwt);
      if (encryptedJwt == null || encryptedJwt.isEmpty) {
        Log.print("isTokenValid: No token found in storage.");
        return false;
      }

      // 1. فك تشفير التوكن المخزن
      final String jwtFull = r(encryptedJwt).toString();
      final String jwt = jwtFull.split(Env.addd)[0];

      final parts = jwt.split('.');
      if (parts.length != 3) {
        Log.print("isTokenValid: Invalid JWT format (parts: ${parts.length})");
        return false;
      }

      // 2. فك Base64 للجزء الأوسط (Payload)
      String payloadPart = parts[1];
      while (payloadPart.length % 4 != 0) {
        payloadPart += '=';
      }

      final String decodedPayload = utf8.decode(base64Url.decode(payloadPart));
      final Map<String, dynamic> payload = jsonDecode(decodedPayload);

      if (!payload.containsKey('exp')) {
        Log.print("isTokenValid: No 'exp' claim in token.");
        return false;
      }

      final int exp = payload['exp'];
      final int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;

      Log.print("isTokenValid: Now=$now, Exp=$exp, Diff=${exp - now}s");

      // اعتبار التوكن منتهي قبل دقيقة للأمان
      final bool valid = exp > (now + 60);
      Log.print("isTokenValid: Result=$valid");
      return valid;
    } catch (e) {
      Log.print("isTokenValid Error: $e");
      return false;
    }
  }

  // ─────────────────────────────────────────────────────────────
  // الفرق عن getJWT:
  //   • يستخدم endpoint مختلف (loginWallet)
  //   • يرجع hmac مع الـ jwt ويخزنه في GetStorage
  //   • الـ JWT لا يُشفَّر ثلاثياً (يُستخدم مباشرة في الـ header)
  // ─────────────────────────────────────────────────────────────
  Future<String?> getJwtWallet() async {
    dev = Platform.isAndroid ? 'android' : 'ios';

    final String fp = box.read(BoxName.deviceFpEncrypted) ?? '';

    var payload = {
      'id': box.read(BoxName.passengerID),
      'password': AK.passnpassenger,
      'aud': '${AK.allowedWallet}$dev',
      'fingerPrint': fp,
    };

    var response = await http.post(
      Uri.parse(AppLink.loginJwtWalletRider),
      body: payload,
    );

    Log.print('AppLink.loginJwtWalletRider: ${AppLink.loginJwtWalletRider}');
    Log.print('response wallet: ${response.body}');

    if (response.statusCode == 200) {
      final decoded = jsonDecode(response.body);

      // ← الإصلاح: نقرأ من message أو data أو root
      final inner = decoded['data'] ?? decoded['message'] ?? decoded;

      final String? jwt = inner['jwt'];
      final String? hmac = inner['hmac'];

      Log.print('jwt extracted: $jwt');
      Log.print('hmac extracted: $hmac');

      if (hmac != null) {
        box.write(BoxName.hmac, hmac);
      }

      return jwt;
    }

    return null;
  }

  Future<void> loginUsingCredentials(String passengerID, String email) async {
    isloading = true;
    update();
    // await getJWT();
    Log.print("LoginController.loginUsingCredentials: ");
    try {
      // 1) استعلام تسجيل الدخول
      final res = await CRUD().get(
        link: AppLink.loginFromGooglePassenger,
        payload: {
          'platform': Platform.isAndroid ? 'android' : 'ios',
          'appName': AppInformation.appName,
        },
      );

      // 2) فك JSON مرة واحدة والتحقق من النجاح
      final decoded = jsonDecode(res);
      if (decoded is! Map || decoded.isEmpty) return;

      if (decoded['status'] == 'failure' || decoded['status'] == 'Failure') {
        Get.snackbar("User does not exist.".tr, '',
            backgroundColor: Colors.red);
        return;
      }

      final status = (decoded['status'] ?? '').toString();
      final data = (decoded['data'] as List?)?.firstOrNull as Map? ?? {};
      if (status != 'success' || data['verified'].toString() != '1') {
        // غير مُفعل -> أذهب للتسجيل بالـ SMS
        Get.offAll(() => PhoneNumberScreen());
        return;
      }

      // 3) كتابة القيم (خفيفة)
      box.write(BoxName.isVerified, '1');
      box.write(BoxName.email, data['email']);
      box.write(BoxName.phone, data['phone']);
      box.write(BoxName.name, data['first_name']);
      box.write(BoxName.isTest, '1');
      box.write(BoxName.package, data['package']);
      box.write(BoxName.promo, data['promo']);
      box.write(BoxName.discount, data['discount']);
      box.write(BoxName.validity, data['validity']);
      box.write(BoxName.isInstall, data['isInstall'] ?? 'none');
      box.write(BoxName.isGiftToken, data['isGiftToken'] ?? 'none');
      box.write(BoxName.isClaim, data['isClaim'] ?? '0');
      if (data['inviteCode'] != null) {
        box.write(BoxName.inviteCode, data['inviteCode'].toString());
      }
      // مهم: تأكد من passengerID في الـ box
      box.write(BoxName.passengerID, passengerID);

      // 4) فحص ما إذا كان التوكن موجوداً في رد الـ Login المدمج (V3 Optimization)
      String? serverFCM;
      String? serverFP;

      var userData = decoded['data'] is List
          ? (decoded['data'] as List).firstOrNull
          : decoded['data'];
      if (userData is Map && userData['fcm_token'] != null) {
        serverFCM = userData['fcm_token'].toString();
        serverFP = userData['fcm_fingerprint']?.toString() ?? '';
        Log.print(
            "✅ FCM Token found in Login response. Skipping separate getTokens call.");
      }

      // إذا لم يكن موجوداً (توافقية قديمة)، نقوم بطلبه
      String? tokenResp;
      if (serverFCM == null) {
        tokenResp = await CRUD().get(
            link: AppLink.getTokens, payload: {'passengerID': passengerID});
      }

      final localFP = (await DeviceHelper.getDeviceFingerprint()).toString();
      await storage.write(key: BoxName.fingerPrint, value: localFP);
      await box.write(BoxName.firstTimeLoadKey, 'false');

      // ── 5. المقارنة: FCM token + fingerprint ──────────────────────
      if (email != '962798583052@intaleqapp.com') {
        if (serverFCM == null &&
            tokenResp != null &&
            tokenResp != 'failure' &&
            tokenResp != 'error') {
          final tokenJson = jsonDecode(tokenResp);
          final serverData = tokenJson['data'] ?? tokenJson['message'];
          if (serverData is Map) {
            serverFCM = serverData['token']?.toString() ?? '';
            serverFP = serverData['fingerPrint']?.toString() ?? '';
          }
        }

        if (serverFCM != null && serverFCM.isNotEmpty) {
          final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();

          // ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
          final fcmChanged = serverFCM != localFCM;
          final fpChanged =
              serverFP != null && serverFP.isNotEmpty && serverFP != localFP;

          if (fcmChanged || fpChanged) {
            mySnackbarInfo('Device Change Detected'.tr);
            await Get.to(() => OtpVerificationPage(
                  phone: data['phone'].toString(),
                  deviceToken: localFP,
                  token: tokenResp ?? '',
                  ptoken: serverFCM ?? '', // نمرر FCM القديم للـ OTP controller
                ));
            return;
          }
        }
      }

      // 6) منطق الدعوة (إن وُجد) ثم الانتقال
      final invite = box.read(BoxName.inviteCode)?.toString() ?? 'none';
      final isInstall = box.read(BoxName.isInstall)?.toString() ?? '0';

      if (invite != 'none' && isInstall != '1') {
        try {
          await CRUD().post(link: AppLink.updatePassengersInvitation, payload: {
            "inviteCode": invite,
            "passengerID": passengerID,
          });

          // سجل الدعوة أيضاً في النظام الموحد الجديد
          await CRUD().post(link: AppLink.addUnifiedInvite, payload: {
            "inviter_code": invite,
          });

          // تحديث الحالة محلياً لضمان عدم إرسال الطلب مرة أخرى
          box.write(BoxName.isInstall, '1');

          await Get.defaultDialog(
            title: 'Invitation Used'.tr,
            middleText: "Your invite code was successfully applied!".tr,
            textConfirm: "OK".tr,
            confirmTextColor: Colors.white,
            onConfirm: () async {
              try {
                await CRUD().post(link: AppLink.addPassengersPromo, payload: {
                  "promoCode":
                      'I-${(box.read(BoxName.name)).toString().split(' ').first}',
                  "amount": '25',
                  "passengerID": passengerID,
                  "description": 'promo first'
                });
              } catch (e) {
                addError(
                    e.toString(), 'promo on invitation in login_controller');
              } finally {
                Get.offAll(() => const MapPagePassenger());
              }
            },
          );
          return;
        } catch (_) {
          // حتى لو فشل، كمل للصفحة الرئيسية
        }
      }

      sendPassengerLocation();
      Get.offAll(() => const MapPagePassenger());
    } catch (e) {
      addError('$e', 'loginUsingCredentials');
      Get.snackbar('Error', e.toString(), backgroundColor: Colors.redAccent);
    } finally {
      isloading = false;
      update();
    }
  }

  // Future<bool?> _confirmDeviceChangeDialog() {
  //   return Get.defaultDialog<bool>(
  //     barrierDismissible: false,
  //     title: 'Device Change Detected'.tr,
  //     middleText: 'Please verify your identity'.tr,
  //     textConfirm: 'Verify'.tr,
  //     confirmTextColor: Colors.white,
  //     onConfirm: () => Get.back(result: true),
  //     textCancel: 'Cancel'.tr,
  //     onCancel: () => Get.back(result: false),
  //   );
  // }

  void loginTester() async {
    isloading = true;
    update();
    
    try {
      var fingerPrint = await DeviceHelper.getDeviceFingerprint();
      var payload = {
        'email': emailController.text.trim(),
        'password': passwordController.text.trim(),
        'fingerPrint': fingerPrint,
        'aud': '${AK.allowed}${Platform.isAndroid ? 'android' : 'ios'}',
      };

      var response = await http.post(
        Uri.parse(AppLink.loginUsingCredentialsWithoutGooglePassenger),
        body: payload,
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        var jsonDecoeded = jsonDecode(response.body);
        if (jsonDecoeded['status'] == 'success' && jsonDecoeded['data'][0]['verified'].toString() == '1') {
          var d = jsonDecoeded['data'][0];
          var jwt = jsonDecoeded['jwt'];

          // حفظ التوكن
          if (jwt != null) {
            box.write(BoxName.jwt, c(jwt));
            await storage.write(key: BoxName.jwt, value: c(jwt));
          }

          box.write(BoxName.isVerified, '1');
          box.write(BoxName.email, d['email']);
          box.write(BoxName.name, d['first_name']);
          box.write(BoxName.phone, d['phone']);
          box.write(BoxName.passengerID, d['id']);
          box.write(BoxName.isTest, '1');

          await storage.write(key: BoxName.fingerPrint, value: fingerPrint);

          sendPassengerLocation();
          Get.offAll(() => const MapPagePassenger());
        } else {
          Get.offAll(() => LoginPage());
          isloading = false;
          update();
        }
      } else {
        isloading = false;
        update();
      }
    } catch (e) {
      Log.print("Tester Login Error: $e");
      isloading = false;
      update();
    }
  }

  void goToMapPage() {
    if (box.read(BoxName.email) != null) {
      Get.offAll(() => const MapPagePassenger());
    }
  }

  final location = Location();

  // late PermissionStatus permissionGranted = PermissionStatus.denied;
  Future<void> getLocationPermission() async {
    bool serviceEnabled;
    PermissionStatus permissionGranted;

    // Check if location services are enabled
    serviceEnabled = await location.serviceEnabled();
    if (!serviceEnabled) {
      serviceEnabled = await location.requestService();
      if (!serviceEnabled) {
        // Location services are still not enabled, handle the error
        return;
      }
    }

    // Check if the app has permission to access location
    permissionGranted = await location.hasPermission();
    if (permissionGranted == PermissionStatus.denied) {
      permissionGranted = await location.requestPermission();
      if (permissionGranted != PermissionStatus.granted) {
        // Location permission is still not granted, handle the error
        permissionGranted = await location.requestPermission();
        return;
      }
    }
    if (permissionGranted.toString() == 'PermissionStatus.granted') {
      box.write(BoxName.locationPermission, 'true');
    }
    update();
  }

  // ─────────────────────────────────────────────────────────────
  // sendPassengerLocation: تسجيل موقع فتح التطبيق للراكب
  // ─────────────────────────────────────────────────────────────
  Future<void> sendPassengerLocation() async {
    try {
      final String? passengerID = box.read(BoxName.passengerID)?.toString();
      if (passengerID == null || passengerID.isEmpty) {
        Log.print("sendPassengerLocation: No passenger ID found, skipping.");
        return;
      }

      // ── [THROTTLING] تحديث الموقع مرة كل 12 ساعة فقط لتقليل الضغط ──
      final String cacheKey = '${BoxName.lastLocationPush}_$passengerID';
      final String? lastUploadStr = box.read(cacheKey);
      if (lastUploadStr != null) {
        final DateTime lastUpload = DateTime.parse(lastUploadStr);
        final Duration diff = DateTime.now().difference(lastUpload);
        if (diff.inHours < 12) {
          Log.print("sendPassengerLocation: Location uploaded recently (${diff.inHours}h ago). Skipping.");
          return;
        }
      }

      // تحقق من تفعيل خدمات الموقع الجغرافي
      bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
      if (!serviceEnabled) {
        Log.print("sendPassengerLocation: Location service disabled.");
        return;
      }

      // التحقق من الصلاحيات والسكوت الممنهج لتفادي النوافذ المزعجة
      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        Log.print("sendPassengerLocation: Permission is denied. Skipping silently.");
        return;
      }
      if (permission == LocationPermission.deniedForever) {
        Log.print("sendPassengerLocation: Permission permanently denied. Skipping silently.");
        return;
      }

      // جلب الموقع الحالي بمهلة 5 ثوانٍ
      final Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.medium,
        timeLimit: const Duration(seconds: 5),
      );

      Log.print("sendPassengerLocation: Got location: ${position.latitude}, ${position.longitude}");

      // إرسال البيانات إلى السيرفر
      final response = await CRUD().post(
        link: AppLink.savePassengerLocation,
        payload: {
          'latitude': position.latitude.toString(),
          'longitude': position.longitude.toString(),
        },
      );

      Log.print("sendPassengerLocation response: $response");

      if (response != 'failure' && response != null) {
        final decoded = response is Map ? response : jsonDecode(response.toString());
        if (decoded['status'] == 'success') {
          box.write(cacheKey, DateTime.now().toIso8601String());
          Log.print("sendPassengerLocation: Location logged and cached successfully.");
        }
      }
    } catch (e) {
      Log.print("sendPassengerLocation error: $e");
    }
  }
}
