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

import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:secure_string_operations/secure_string_operations.dart';

import '../../constant/api_key.dart';
import '../../constant/box_name.dart';
import '../../constant/char_map.dart';
import '../../constant/info.dart';
import '../../constant/links.dart';
import '../../env/env.dart';
import '../../main.dart';
import '../../print.dart';
import 'device_info.dart';
import 'encrypt_decrypt.dart';
import 'security_checks.dart';

class CRUD {
  var dev = '';
  getJWT() async {
    // إذا كان الأدمن مسجل دخوله بالفعل، لا تقم بتوليد توكن "ضيف" قديم
    if (box.read(BoxName.driverID) != null) {
      Log.print('Admin session active. Skipping guest JWT.');
      return;
    }

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

    var payload = {
      'id': 'admin',
      'password': AK.passnpassenger,
      'aud': '${AK.allowed}$dev',
    };
    Log.print('payload: ${payload}');
    var response1 = await http.post(
      Uri.parse(AppLink.loginJwtDriver),
      body: payload,
    );

    if (response1.statusCode == 200) {
      final decodedResponse1 = jsonDecode(response1.body);

      final jwt = decodedResponse1['jwt'];
      Log.print('jwt: ${jwt}');
      await box.write(BoxName.jwt, X.c(X.c(X.c(jwt, cn), cC), cs));
      // await AppInitializer().getKey();
    }
  }

  Future<dynamic> get({
    required String link,
    Map<String, dynamic>? payload,
  }) async {
    String token = '';
    var rawJwt = box.read(BoxName.jwt);

    if (rawJwt == null) {
      await getJWT();
      rawJwt = box.read(BoxName.jwt);
    }

    if (rawJwt != null) {
      token = r(rawJwt.toString()).split(AppInformation.addd)[0];
      try {
        if (JwtDecoder.isExpired(token)) {
          // If we have an admin ID, we should probably re-login or refresh,
          // but for now let's just fall back to guest JWT if needed.
          if (box.read(BoxName.driverID) == null) {
            await getJWT();
            token = r(box.read(BoxName.jwt).toString())
                .split(AppInformation.addd)[0];
          }
        }
      } catch (e) {
        print('❌ JWT Decode Error: $e');
        // If decryption failed, try using raw (maybe it was saved plain)
        token = rawJwt.toString().split(AppInformation.addd)[0];
      }
    }
    var url = Uri.parse(link);
    Log.print('--- [CRUD GET] ---');
    Log.print('URL: $link');
    Log.print('Payload: $payload');

    var response = await http.post(
      url,
      body: payload,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        'Authorization': 'Bearer $token',
        'X-Device-FP': box.read(BoxName.fingerPrint) ?? '',
      },
    );

    Log.print('Status Code: ${response.statusCode}');
    Log.print('Response Body: ${response.body}');
    Log.print('------------------');

    if (response.statusCode == 200) {
      try {
        var jsonData = jsonDecode(response.body);
        if (jsonData['status'] == 'success') {
          return response.body;
        }
        return jsonData['status'] ?? 'failure';
      } catch (e) {
        return 'failure';
      }
    } else if (response.statusCode == 401) {
      return 'token_expired';
    } else {
      return 'failure';
    }
  }

  Future<dynamic> post(
      {required String link, Map<String, dynamic>? payload}) async {
    var url = Uri.parse(link);
    try {
      String token = '';
      var rawJwt = box.read(BoxName.jwt);

      if (rawJwt != null) {
        token = r(rawJwt.toString()).split(AppInformation.addd)[0];
        try {
          if (JwtDecoder.isExpired(token)) {
            if (box.read(BoxName.driverID) == null) {
              await getJWT();
              token = r(box.read(BoxName.jwt).toString())
                  .split(AppInformation.addd)[0];
            }
          }
        } catch (e) {
          token = rawJwt.toString().split(AppInformation.addd)[0];
        }
      }

      Log.print('--- [CRUD POST] ---');
      Log.print('URL: $link');
      Log.print('Payload: $payload');

      var response = await http.post(
        url,
        body: payload,
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
          'Authorization': 'Bearer $token',
          'X-Device-FP': box.read(BoxName.fingerPrint) ?? '',
        },
      );

      Log.print('Status Code: ${response.statusCode}');
      Log.print('Response Body: ${response.body}');
      Log.print('-------------------');

      if (response.statusCode == 200) {
        try {
          var jsonData = jsonDecode(response.body);
          if (jsonData['status'] == 'success') {
            return jsonData;
          } else {
            return jsonData['status'];
          }
        } catch (e) {
          return 'failure';
        }
      } else if (response.statusCode == 401) {
        return 'token_expired';
      } else {
        return 'failure';
      }
    } catch (e) {
      // addError('HTTP request error: $e', 'crud().post - HTTP');
      return 'failure';
    }
  }

  getJwtWallet() async {
    // 1. فحص التوكن المخزن أولاً (Caching) لتقليل طلبات الـ SSO
    var cachedWalletJwt = box.read('wallet_jwt');
    var cachedWalletExpiry = box.read('wallet_jwt_expiry');

    if (cachedWalletJwt != null && cachedWalletExpiry != null) {
      int expiryMs = int.tryParse(cachedWalletExpiry.toString()) ?? 0;
      // إذا لم ينته بعد (مع هامش أمان 60 ثانية)
      if (DateTime.now().millisecondsSinceEpoch < expiryMs - 60000) {
        Log.print(
            'Using cached Wallet JWT. Expiry: ${DateTime.fromMillisecondsSinceEpoch(expiryMs)}');
        return cachedWalletJwt.toString();
      }
    }

    String fingerPrint = await DeviceHelper.getDeviceFingerprint();
    final mainTokenEnc = box.read(BoxName.jwt);
    if (mainTokenEnc == null) return null;

    String mainToken = mainTokenEnc.toString();
    // فك تشفير التوكن بنفس طريقة دالة get() التي تعمل بنجاح
    try {
      mainToken = r(mainTokenEnc.toString()).split(AppInformation.addd)[0];
    } catch (e) {
      // إذا فشل فك التشفير، نستخدم القيمة كما هي (ربما مخزنة بدون تشفير)
      mainToken = mainTokenEnc.toString().split(AppInformation.addd)[0];
    }
    Log.print('Wallet SSO mainToken length: ${mainToken.length}');
    Log.print(
        'Wallet SSO token starts with: ${mainToken.substring(0, mainToken.length > 10 ? 10 : mainToken.length)}');

    // استخدام الـ SSO للسيرفر الرئيسي إذا كان الأدمن مسجل دخوله
    var response1 = await http.post(
      Uri.parse(AppLink.loginWalletAdminV3),
      headers: {
        'Authorization': 'Bearer $mainToken',
        'X-Device-FP': fingerPrint,
      },
    );

    Log.print('Wallet SSO login status: ${response1.statusCode}');

    if (response1.statusCode == 200) {
      final decoded = jsonDecode(response1.body);
      final msg = decoded['message'];

      String? jwt;
      String? hmac;

      if (msg is Map) {
        jwt = msg['jwt'];
        hmac = msg['hmac'];
      } else {
        jwt = decoded['jwt'];
        hmac = decoded['hmac'];
      }

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

      // تخزين التوكن الجديد في الكاش لمدة 10 دقائق (600 ثانية)
      if (jwt != null) {
        await box.write('wallet_jwt', jwt);
        await box.write('wallet_jwt_expiry',
            (DateTime.now().millisecondsSinceEpoch + (600 * 1000)).toString());
        Log.print('Wallet JWT cached successfully.');
      }

      return jwt?.toString();
    } else {
      // Fallback: المحاولة بالطريقة القديمة إذا فشل الـ SSO
      var payload = {
        'id': box.read(BoxName.driverID) ?? '1',
        'password': AK.passnpassenger,
        'aud': '${Env.allowedWallet}${Platform.isAndroid ? 'android' : 'ios'}',
        'fingerPrint': fingerPrint
      };
      var fallbackRes = await http.post(
        Uri.parse(AppLink.loginWalletAdmin),
        body: payload,
      );
      if (fallbackRes.statusCode == 200) {
        final decoded = jsonDecode(fallbackRes.body);
        if (decoded['jwt'] != null) return decoded['jwt'].toString();
      }
    }
    return null;
  }

  Future<dynamic> getWallet({
    required String link,
    Map<String, dynamic>? payload,
    bool isRetry = false,
  }) async {
    var s = await getJwtWallet();
    final hmac = box.read(BoxName.hmac);
    var url = Uri.parse(link);

    Log.print('--- getWallet Execution ---');
    Log.print('URL: $url');
    Log.print('JWT: $s');
    Log.print('HMAC: $hmac');
    Log.print('Is Retry: $isRetry');
    Log.print('Payload: $payload');

    if (payload != null && hmac != null) {
      payload['hmac'] = hmac.toString();
    }

    try {
      var response = await http.post(
        url,
        body: payload,
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
          'Authorization': 'Bearer $s',
          'X-HMAC-Auth': hmac.toString(),
          'X-Device-FP': box.read(BoxName.fingerPrint) ?? '',
        },
      );

      Log.print('Status Code: ${response.statusCode}');
      Log.print('Response Body: ${response.body}');

      if (response.statusCode == 200) {
        try {
          var jsonData = jsonDecode(response.body);
          if (jsonData['status'] == 'success') {
            return jsonData;
          }
          Log.print('Logic Error: Status is not success. Data: $jsonData');
          return jsonData['status'] ?? 'failure';
        } catch (e) {
          Log.print('JSON Decode Error in getWallet: $e');
          return 'failure';
        }
      } else if (response.statusCode == 401 && !isRetry) {
        Log.print('Token expired (401). Clearing cache and retrying...');
        await box.remove('wallet_jwt');
        await box.remove('wallet_jwt_expiry');
        return await getWallet(link: link, payload: payload, isRetry: true);
      } else {
        Log.print('HTTP Error in getWallet. Status: ${response.statusCode}');
        return 'failure';
      }
    } catch (e) {
      Log.print('HTTP Request Exception in getWallet: $e');
      return 'failure';
    }
  }

  Future<dynamic> postWallet(
      {required String link, Map<String, dynamic>? payload}) async {
    var s = await getJwtWallet();
    Log.print('jwt: ${s}');
    final hmac = box.read(BoxName.hmac);
    Log.print('hmac: ${hmac}');
    var url = Uri.parse(link);
    Log.print('url: ${url}');

    // إضافة الـ HMAC للـ payload لزيادة التوافقية
    if (payload != null && hmac != null) {
      payload['hmac'] = hmac.toString();
    }

    try {
      // await LoginDriverController().getJWT();

      var response = await http.post(
        url,
        body: payload,
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
          'Authorization': 'Bearer $s',
          'X-HMAC-Auth': hmac.toString(),
          'X-Device-FP': box.read(BoxName.fingerPrint) ?? '',
        },
      );
      // Log.print('response.request:${response.request}');
      // Log.print('response.body: ${response.body}');
      // Log.print('payload:$payload');
      if (response.statusCode == 200) {
        try {
          var jsonData = jsonDecode(response.body);
          if (jsonData['status'] == 'success') {
            return jsonData;
          }
          return jsonData['status'] ?? 'failure';
        } catch (e) {
          return 'failure';
        }
      } else if (response.statusCode == 401) {
        await getJwtWallet();
        return 'token_expired';
      } else {
        return 'failure';
      }
    } catch (e) {
      // addError('HTTP request error: $e', 'crud().post - HTTP');
      return 'failure';
    }
  }

  // }
  Future sendWhatsAppAuth(String to, message) async {
    var res = await CRUD().post(
        link: AppLink.send_whatsapp_message,
        payload: {'receiver': to, 'message': message});
    if (res != 'failure') {
      Get.snackbar('Success', 'Message sent successfully');
    } else {
      Get.snackbar('Error', 'Failed to send message');
    }
  }

  Future<dynamic> getAgoraToken({
    required String channelName,
    required String uid,
  }) async {
    var uid = box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver);
    var res = await http.get(
        Uri.parse(
            'https://repulsive-pig-rugby-shirt.cyclic.app/token?channelName=$channelName'),
        headers: {'Authorization': 'Bearer ${AK.agoraAppCertificate}'});

    if (res.statusCode == 200) {
      var response = jsonDecode(res.body);
      return response['token'];
    } else {}
  }

  Future<dynamic> getLlama({
    required String link,
    required String payload,
    required String prompt,
  }) async {
    var url = Uri.parse(
      link,
    );
    var headers = {
      'Content-Type': 'application/json',
      'Authorization':
          'Bearer LL-X5lJ0Px9CzKK0HTuVZ3u2u4v3tGWkImLTG7okGRk4t25zrsLqJ0qNoUzZ2x4ciPy'
      // 'Authorization': 'Bearer ${Env.llamaKey}'
    };
    var data = json.encode({
      "model": "Llama-3-70b-Inst-FW",
      // "model": "llama-13b-chat",
      "messages": [
        {
          "role": "user",
          "content":
              "Extract the desired information from the following passage as json decoded like $prompt just in this:\n\n$payload"
        }
      ],
      "temperature": 0.9
    });
    var response = await http.post(
      url,
      body: data,
      headers: headers,
    );

    if (response.statusCode == 200) {
      return response.body;
    }
    return response.statusCode;
  }

  Future allMethodForAI(String prompt, driverID, imagePath) async {
    // await ImageController().choosImage(linkPHP, imagePath);
    Future.delayed(const Duration(seconds: 2));
    var extractedString = await arabicTextExtractByVisionAndAI(
        imagePath: imagePath, driverID: driverID);
    var json = jsonDecode(extractedString);
    var textValues = getAllTextValuesWithLineNumbers(json);
    // List<String> textValues = getAllTextValues(json);

    // await AI().geminiAiExtraction(prompt, textValues);
  }

  Map<String, List<Map<String, String>>> getAllTextValuesWithLineNumbers(
      Map json) {
    Map<String, List<Map<String, String>>> output = {};
    int lineNumber = 1;

    if (json.containsKey('regions')) {
      List<dynamic> regions = json['regions'];
      for (Map<String, dynamic> region in regions) {
        if (region.containsKey('lines')) {
          List<dynamic> lines = region['lines'];
          List<Map<String, String>> linesWithText = [];
          for (Map<String, dynamic> line in lines) {
            if (line.containsKey('words')) {
              List<dynamic> words = line['words'];
              String lineText = "";
              for (Map<String, dynamic> word in words) {
                if (word.containsKey('text')) {
                  lineText += word['text'] + " ";
                }
              }
              lineText = lineText.trim();
              linesWithText.add(
                  {"line_number": lineNumber.toString(), "text": lineText});
              lineNumber++;
            }
          }
          output["region_${region.hashCode}"] = linesWithText;
        }
      }
    }

    return output;
  }

  // List<String> getAllTextValues(Map json) {
  //   List<String> textValues = [];

  //   if (json.containsKey('regions')) {
  //     List<dynamic> regions = json['regions'];
  //     for (Map<String, dynamic> region in regions) {
  //       if (region.containsKey('lines')) {
  //         List<dynamic> lines = region['lines'];
  //         for (Map<String, dynamic> line in lines) {
  //           if (line.containsKey('words')) {
  //             List<dynamic> words = line['words'];
  //             for (Map<String, dynamic> word in words) {
  //               if (word.containsKey('text')) {
  //                 textValues.add(word['text']);
  //               }
  //             }
  //           }
  //         }
  //       }
  //     }
  //   }

  //   return textValues;
  // }

  Future<dynamic> arabicTextExtractByVisionAndAI({
    required String imagePath,
    required String driverID,
  }) async {
    var headers = {
      'Content-Type': 'application/json',
      'Ocp-Apim-Subscription-Key': AK.ocpApimSubscriptionKey
    };

    String imagePathFull =
        '${AppLink.server}/card_image/$imagePath-$driverID.jpg';
    var request = http.Request(
        'POST',
        Uri.parse(
            'https://eastus.api.cognitive.microsoft.com/computervision/imageanalysis:analyze?features=caption,read&model-version=latest&language=en&api-version=2024-02-01'));
    request.body = json.encode({"url": imagePathFull});
    request.headers.addAll(headers);

    http.StreamedResponse response = await request.send();

    if (response.statusCode == 200) {
      return await response.stream.bytesToString();
    } else {}
  }

  Future<dynamic> getChatGPT({
    required String link,
    required String payload,
  }) async {
    var url = Uri.parse(
      link,
    );
    var headers = {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ${Env.chatGPTkeySeferNew}'
    };
    var data = json.encode({
      "model": "gpt-3.5-turbo",
      "messages": [
        {
          "role": "user",
          "content":
              "Extract the desired information from the following passage as json decoded like vin,make,made,year,expiration_date,color,owner,registration_date just in this:\n\n$payload"
        }
      ],
      "temperature": 0.9
    });
    var response = await http.post(
      url,
      body: data,
      headers: headers,
    );

    if (response.statusCode == 200) {
      return response.body;
    }
    return response.statusCode;
  }


  Future<dynamic> kazumiSMS({
    required String link,
    Map<String, dynamic>? payload,
  }) async {
    var url = Uri.parse(
      link,
    );
    var headers = {'Content-Type': 'application/json'};
    var request = http.Request('POST', url);
    request.body = json.encode({
      "username": "Sefer",
      "password": AK.smsPasswordEgypt,
    });
    request.headers.addAll(headers);

    http.StreamedResponse response = await request.send();

    if (response.statusCode == 200) {
      var responseBody = await response.stream.bytesToString();
      var data = json.decode(responseBody);
      return data;
    } else {}
  }

  Future<dynamic> sendSmsEgypt(String phone, otp) async {
    // String sender = await getSender();
    var headers = {'Content-Type': 'application/json'};
    var body = jsonEncode({
      "username": "Sefer",
      "password": "E)Pu=an/@Z",
      "message": otp,
      "language": "e",
      "sender": "Sefer Egy",
      "receiver": phone
    });

    var res = await http.post(
      Uri.parse(AppLink.sendSms),
      body: body,
      headers: headers,
    );
  }

  Future<dynamic> postPayMob({
    required String link,
    Map<String, dynamic>? payload,
  }) async {
    // String? basicAuthCredentials =
    //     await storage.read(key: BoxName.basicAuthCredentials);
    var url = Uri.parse(
      link,
    );
    var response = await http.post(url,
        body: payload, headers: {'Content-Type': 'application/json'});

    var jsonData = jsonDecode(response.body);
    if (response.statusCode == 200) {
      if (jsonData['status'] == 'success') {
        return response.body;
      } else {
        return (jsonData['status']);
      }
    } else {
      return response.statusCode;
    }
  }

  sendEmail(
    String link,
    Map<String, String>? payload,
  ) async {
    var headers = {
      "Content-Type": "application/x-www-form-urlencoded",
      'Authorization':
          'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
    };
    var request = http.Request('POST', Uri.parse(link));
    request.bodyFields = payload!;
    request.headers.addAll(headers);

    http.StreamedResponse response = await request.send();
    if (response.statusCode == 200) {
    } else {}
  }

  Future<dynamic> postFromDialogue({
    required String link,
    Map<String, dynamic>? payload,
  }) async {
    // String? basicAuthCredentials =
    //     await storage.read(key: BoxName.basicAuthCredentials);
    var url = Uri.parse(
      link,
    );
    var response = await http.post(
      url,
      body: payload,
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        'Authorization':
            'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
      },
    );

    if (response.body.isNotEmpty) {
      var jsonData = jsonDecode(response.body);
      if (response.statusCode == 200) {
        if (jsonData['status'] == 'success') {
          Get.back();
          // Get.snackbar(
          //   jsonData['status'],
          //   jsonData['message'],
          // );

          return response.body;
        }
      }
      return (jsonData['status']);
    }
  }

  Future<void> sendVerificationRequest(String phoneNumber) async {
    final accountSid = AK.accountSIDTwillo;
    final authToken = AK.authTokenTwillo;
    final verifySid = AK.twilloRecoveryCode;

    final Uri verificationUri = Uri.parse(
        'https://verify.twilio.com/v2/Services/$verifySid/Verifications');

    // Send the verification request
    final response = await http.post(
      verificationUri,
      headers: {
        'Authorization':
            'Basic ${base64Encode(utf8.encode('$accountSid:$authToken'))}',
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: {
        'To': phoneNumber,
        'Channel': 'sms',
      },
    );

    if (response.statusCode == 201) {
    } else {}

    // Prompt the user to enter the OTP
    const otpCode = "123456"; // Replace with user input

    // Check the verification code
    final checkUri = Uri.parse(
        'https://verify.twilio.com/v2/Services/$verifySid/VerificationCheck');

    final checkResponse = await http.post(
      checkUri,
      headers: {
        'Authorization':
            'Basic ${base64Encode(utf8.encode('$accountSid:$authToken'))}',
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: {
        'To': phoneNumber,
        'Code': otpCode,
      },
    );

    if (checkResponse.statusCode == 201) {
    } else {}
  }

  Future<dynamic> getGoogleApi({
    required String link,
    Map<String, dynamic>? payload,
  }) async {
    var url = Uri.parse(
      link,
    );
    var response = await http.post(
      url,
      body: payload,
    );
    var jsonData = jsonDecode(response.body);
    if (jsonData['status'] == 'OK') {
      return jsonData;
    }
    return (jsonData['status']);
  }

  Future<dynamic> update({
    required String endpoint,
    required Map<String, dynamic> data,
    required String id,
  }) async {
    // String? basicAuthCredentials =
    //     await storage.read(key: BoxName.basicAuthCredentials);
    var url = Uri.parse('$endpoint/$id');
    var response = await http.put(
      url,
      body: json.encode(data),
      headers: {
        'Authorization':
            'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
      },
    );
    return json.decode(response.body);
  }

  Future<dynamic> delete({
    required String endpoint,
    required String id,
  }) async {
    // String? basicAuthCredentials =
    //     await storage.read(key: BoxName.basicAuthCredentials);
    var url = Uri.parse('$endpoint/$id');
    var response = await http.delete(
      url,
      headers: {
        'Authorization':
            'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
      },
    );
    return json.decode(response.body);
  }

  List phoneDriversTest = [
    201023248456,
    201023248456,
  ];
}
