import 'dart:convert';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_contacts/contact.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:get/get.dart';
import 'package:local_auth/local_auth.dart';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/constant/links.dart';
import 'package:sefer_driver/controller/functions/crud.dart';
import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart';
import 'package:sefer_driver/main.dart';
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import 'package:share_plus/share_plus.dart';

import '../../firebase/local_notification.dart';
import '../../functions/launch.dart';
import '../../notification/notification_captain_controller.dart';

class InviteController extends GetxController {
  final TextEditingController invitePhoneController = TextEditingController();
  List driverInvitationData = [];
  List driverInvitationDataToPassengers = [];
  String? couponCode;
  String? driverCouponCode;

  // **FIX**: Added the missing 'contacts' and 'contactMaps' definitions.
  List<Contact> contacts = [];
  RxList<Map<String, dynamic>> contactMaps = <Map<String, dynamic>>[].obs;

  int selectedTab = 0;
  PassengerStats passengerStats = PassengerStats();
  void updateSelectedTab(int index) {
    selectedTab = index;
    update();
  }

  Future<void> shareDriverCode() async {
    if (driverCouponCode != null) {
      final String shareText =
          '''Join Intaleq as a driver using my referral code!
Use code: $driverCouponCode
Download the Intaleq Driver app now and earn rewards!
''';
      await Share.share(shareText);
    }
  }

  Future<void> sharePassengerCode() async {
    if (couponCode != null) {
      final String shareText = '''Get a discount on your first Intaleq ride!
Use my referral code: $couponCode
Download the Intaleq app now and enjoy your ride!
''';
      await Share.share(shareText);
    }
  }

  @override
  void onInit() {
    super.onInit();
    // **MODIFIED**: Sync contacts automatically on controller initialization.
    syncContactsToServerOnce();
    // fetchDriverStats();
  }

  // --- NEW LOGIC: ONE-TIME CONTACTS SYNC ---

  /// **NEW**: Syncs all phone contacts to the server, but only runs once per user.
  Future<void> syncContactsToServerOnce() async {
    final String syncFlagKey = 'contactsSynced_${box.read(BoxName.driverID)}';

    // 1. Check if contacts have already been synced for this user.
    if (box.read(syncFlagKey) == true) {
      print("Contacts have already been synced for this user.");
      return;
    }

    try {
      // 2. Request permission and fetch all contacts.
      if (await FlutterContacts.requestPermission(readonly: true)) {
        //  mySnackbarSuccess('Starting contacts sync in background...'.tr);
        final List<Contact> allContacts =
            await FlutterContacts.getContacts(withProperties: true);
        // **FIX**: Assign fetched contacts to the class variable.
        contacts = allContacts;
        contactMaps.value = contacts.map((contact) {
          return {
            'name': contact.displayName,
            'phones':
                contact.phones.map((phone) => phone.normalizedNumber).toList(),
            'emails': contact.emails.map((email) => email.address).toList(),
          };
        }).toList();
        update();

        // 3. Loop through contacts and save them to the server.
        for (var contact in allContacts) {
          if (contact.phones.isNotEmpty) {
            // Use the normalized phone number for consistency.
            var phone = contact.phones.first.normalizedNumber;
            if (phone.isNotEmpty) {
              CRUD().post(link: AppLink.savePhonesSyria, payload: {
                "driverId": box.read(BoxName.driverID), // Associate with driver
                "name": contact.displayName ?? 'No Name',
                "phone": phone,
              });
            }
          }
        }

        // 4. After a successful sync, set the flag to prevent future syncs.
        await box.write(syncFlagKey, true);
        // mySnackbarSuccess('Contacts sync completed successfully!'.tr);
      }
    } catch (e) {
      // mySnackeBarError('An error occurred during contact sync: $e'.tr);
    }
  }

  // --- NEW LOGIC: NATIVE CONTACT PICKER ---

  /// **MODIFIED**: This function now opens the phone's native contact picker.
  Future<void> pickContactFromNativeApp() async {
    try {
      log('=== START: FETCHING ALL CONTACTS FOR BOTTOM SHEET ===',
          name: 'ContactPicker');

      if (await FlutterContacts.requestPermission(readonly: true)) {
        // عرض شاشة تحميل بسيطة ريثما يتم جلب الأسماء
        Get.dialog(const Center(child: CircularProgressIndicator()),
            barrierDismissible: false);

        log('Permission granted. Calling FlutterContacts.getContacts()...',
            name: 'ContactPicker');

        // جلب جميع جهات الاتصال إجبارياً من الصفر مع خصائصها
        List<Contact> allContacts =
            await FlutterContacts.getContacts(withProperties: true);

        log('Total Contacts Fetched from Device: ${allContacts.length}',
            name: 'ContactPicker');

        // فصل الأسماء لمعرفة الخلل
        List<Contact> validContacts = [];
        List<Contact> invalidContacts = [];

        for (var c in allContacts) {
          if (c.phones.isNotEmpty) {
            validContacts.add(c);
          } else {
            invalidContacts.add(c);
          }
        }

        log('Contacts WITH phone numbers: ${validContacts.length}',
            name: 'ContactPicker');
        log('Contacts WITHOUT phone numbers: ${invalidContacts.length}',
            name: 'ContactPicker');

        // طباعة أول 20 اسم صالح
        log('--- Sample of VALID Contacts ---', name: 'ContactPicker');
        for (int i = 0; i < validContacts.length && i < 20; i++) {
          log('[$i] Name: ${validContacts[i].displayName}, Phone: ${validContacts[i].phones.first.number}',
              name: 'ContactPicker');
        }

        // طباعة أول 20 اسم غير صالح (بدون أرقام) لفحص المشكلة
        log('--- Sample of INVALID Contacts (No Phone) ---',
            name: 'ContactPicker');
        for (int i = 0; i < invalidContacts.length && i < 20; i++) {
          log('[$i] Name: ${invalidContacts[i].displayName}',
              name: 'ContactPicker');
        }

        Get.back(); // إغلاق شاشة التحميل

        if (validContacts.isEmpty) {
          mySnackeBarError('No contacts with phone numbers found'.tr);
          return;
        }

        // متغيرات للبحث داخل القائمة المنسدلة
        RxList<Contact> filteredContacts = validContacts.obs;
        TextEditingController searchController = TextEditingController();

        // دالة لتنظيف النصوص من أي رموز معطوبة
        String sanitizeText(String input) {
          if (input.isEmpty) return '';
          return input
              .replaceAll(
                  RegExp(r'[^\x00-\x7F\u0600-\u06FF\u08A0-\u08FF\p{L}\p{N}\s]'),
                  '')
              .trim();
        }

        // فتح دليل هاتف مخصص داخل التطبيق
        Get.bottomSheet(
          Container(
            height: Get.height * 0.85,
            decoration: BoxDecoration(
              color: Theme.of(Get.context!).scaffoldBackgroundColor,
              borderRadius:
                  const BorderRadius.vertical(top: Radius.circular(20)),
            ),
            child: Column(
              children: [
                Container(
                  margin: const EdgeInsets.only(top: 10, bottom: 10),
                  width: 50,
                  height: 5,
                  decoration: BoxDecoration(
                      color: Colors.grey[400],
                      borderRadius: BorderRadius.circular(10)),
                ),
                Text("Select a Contact".tr,
                    style: const TextStyle(
                        fontSize: 18, fontWeight: FontWeight.bold)),
                Padding(
                  padding: const EdgeInsets.all(12.0),
                  child: TextField(
                    controller: searchController,
                    decoration: InputDecoration(
                      hintText: "Search name or number...".tr,
                      prefixIcon: const Icon(Icons.search),
                      border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(10)),
                      contentPadding: const EdgeInsets.symmetric(vertical: 0),
                    ),
                    onChanged: (value) {
                      filteredContacts.value = validContacts.where((c) {
                        final nameMatch = c.displayName
                            .toLowerCase()
                            .contains(value.toLowerCase());
                        final phoneMatch =
                            c.phones.first.number.contains(value);
                        return nameMatch || phoneMatch;
                      }).toList();
                    },
                  ),
                ),
                Expanded(
                  child: Obx(() => ListView.builder(
                        itemCount: filteredContacts.length,
                        itemBuilder: (context, index) {
                          Contact c = filteredContacts[index];
                          var firstPhone = c.phones.first;

                          String selectedPhone =
                              firstPhone.normalizedNumber.isNotEmpty
                                  ? firstPhone.normalizedNumber
                                  : firstPhone.number;

                          String safeName = sanitizeText(c.displayName);
                          if (safeName.isEmpty) safeName = 'Unknown'.tr;

                          String safePhone = sanitizeText(selectedPhone);
                          String initial = safeName.isNotEmpty
                              ? safeName[0].toUpperCase()
                              : '?';

                          return ListTile(
                            leading: CircleAvatar(
                              backgroundColor:
                                  Colors.blueAccent.withOpacity(0.1),
                              child: Text(initial,
                                  style: const TextStyle(
                                      color: Colors.blueAccent)),
                            ),
                            title: Text(safeName),
                            subtitle: Text(safePhone,
                                textDirection: TextDirection.ltr),
                            onTap: () {
                              selectPhone(selectedPhone);
                            },
                          );
                        },
                      )),
                ),
              ],
            ),
          ),
          isScrollControlled: true,
        );
      } else {
        log('Permission DENIED', name: 'ContactPicker');
        mySnackeBarError('Contact permission is required to pick contacts'.tr);
      }
    } catch (e) {
      if (Get.isDialogOpen ?? false) Get.back();
      log('CRITICAL ERROR: $e', name: 'ContactPicker');
      mySnackeBarError('An error occurred while loading contacts: $e'.tr);
    }
    log('=== END: FETCHING CONTACTS ===', name: 'ContactPicker');
  }

  /// **FIX**: Added the missing 'selectPhone' method.
  void selectPhone(String phone) {
    // Format the selected phone number and update the text field.
    invitePhoneController.text = _formatSyrianPhoneNumber(phone);
    update();
    Get.back(); // Close the contacts dialog after selection.
  }

  void fetchDriverStats() async {
    try {
      var response = await CRUD().get(link: AppLink.getInviteDriver, payload: {
        "driverId": box.read(BoxName.driverID),
      });
      if (response != 'failure') {
        var data = jsonDecode(response);
        driverInvitationData = data['message'];
        update();
      }
    } catch (e) {
      // Handle error gracefully
    }
  }

  void fetchDriverStatsPassengers() async {
    try {
      var response = await CRUD()
          .get(link: AppLink.getDriverInvitationToPassengers, payload: {
        "driverId": box.read(BoxName.driverID),
      });
      if (response != 'failure') {
        var data = jsonDecode(response);
        driverInvitationDataToPassengers = data['message'];
        update();
      }
    } catch (e) {
      // Handle error gracefully
    }
  }

  void onSelectDriverInvitation(int index) async {
    MyDialog().getDialog(
      int.parse((driverInvitationData[index]['countOfInvitDriver'])) < 100
          ? '${'When'.tr} ${(driverInvitationData[index]['invitorName'])} ${"complete, you can claim your gift".tr} '
          : 'You deserve the gift'.tr,
      '${(driverInvitationData[index]['invitorName'])} ${(driverInvitationData[index]['countOfInvitDriver'])} / 100 ${'Trip'.tr}',
      () async {
        bool isAvailable = await LocalAuthentication().isDeviceSupported();
        if (int.parse((driverInvitationData[index]['countOfInvitDriver'])) <
            100) {
          Get.back();
        } else if (isAvailable) {
          bool didAuthenticate = await LocalAuthentication().authenticate(
            localizedReason: 'Use Touch ID or Face ID to confirm payment',
            // options: const AuthenticationOptions(
            biometricOnly: true,
            sensitiveTransaction: true,
          );
          if (didAuthenticate) {
            if ((driverInvitationData[index]['isGiftToken']).toString() ==
                '0') {
              Get.back();
              await CRUD().post(
                  link: AppLink.updateInviteDriver,
                  payload: {'id': (driverInvitationData[index]['id'])});
              await Get.find<CaptainWalletController>().addDriverPayment(
                'paymentMethod',
                ('500'),
                '',
              );
              await Get.find<CaptainWalletController>()
                  .addDriverWalletToInvitor(
                'paymentMethod',
                (driverInvitationData[index]['driverInviterId']),
                ('500'),
              );
              NotificationCaptainController().addNotificationCaptain(
                  driverInvitationData[index]['driverInviterId'].toString(),
                  "You have got a gift for invitation".tr,
                  '${"You have 500".tr} ${'SYP'.tr}',
                  false);
              NotificationController().showNotification(
                  "You have got a gift for invitation".tr,
                  '${"You have 500".tr} ${'SYP'.tr}',
                  'tone1',
                  '');
            } else {
              Get.back();
              MyDialog().getDialog("You have got a gift".tr,
                  "Share the app with another new driver".tr, () => Get.back());
            }
          } else {
            MyDialog()
                .getDialog('Authentication failed'.tr, '', () => Get.back());
          }
        } else {
          MyDialog().getDialog(
              'Biometric Authentication'.tr,
              'You should use Touch ID or Face ID to confirm payment'.tr,
              () => Get.back());
        }
      },
    );
  }

  void onSelectPassengerInvitation(int index) async {
    bool isAvailable = await LocalAuthentication().isDeviceSupported();
    MyDialog().getDialog(
      int.parse(driverInvitationDataToPassengers[index]['countOfInvitDriver']
                  .toString()) <
              3
          ? '${'When'.tr} ${(driverInvitationDataToPassengers[index]['passengerName'].toString())} ${"complete, you can claim your gift".tr} '
          : 'You deserve the gift'.tr,
      '${(driverInvitationDataToPassengers[index]['passengerName'].toString())} ${driverInvitationDataToPassengers[index]['countOfInvitDriver']} / 3 ${'Trip'.tr}',
      () async {
        if (int.parse(driverInvitationDataToPassengers[index]
                    ['countOfInvitDriver']
                .toString()) <
            3) {
          Get.back();
        } else if (isAvailable) {
          bool didAuthenticate = await LocalAuthentication().authenticate(
            localizedReason: 'Use Touch ID or Face ID to confirm payment',
            // options: const AuthenticationOptions(
            biometricOnly: true,
            sensitiveTransaction: true,
          );
          if (didAuthenticate) {
            if (driverInvitationDataToPassengers[index]['isGiftToken']
                    .toString() ==
                '0') {
              Get.back();
              await Get.find<CaptainWalletController>()
                  .addDriverWallet('paymentMethod', '200', '200');
              await Get.find<CaptainWalletController>()
                  .addDriverWalletToInvitor('paymentMethod',
                      driverInvitationData[index]['driverInviterId'], '200');
              await CRUD().post(
                link: AppLink.updatePassengerGift,
                payload: {'id': driverInvitationDataToPassengers[index]['id']},
              );
              NotificationCaptainController().addNotificationCaptain(
                driverInvitationDataToPassengers[index]['passengerInviterId']
                    .toString(),
                "You have got a gift for invitation".tr,
                '${"You have 200".tr} ${'SYP'.tr}',
                false,
              );
            } else {
              Get.back();
              MyDialog().getDialog(
                "You have got a gift".tr,
                "Share the app with another new passenger".tr,
                () => Get.back(),
              );
            }
          } else {
            MyDialog()
                .getDialog('Authentication failed'.tr, '', () => Get.back());
          }
        } else {
          MyDialog().getDialog(
              'Biometric Authentication'.tr,
              'You should use Touch ID or Face ID to confirm payment'.tr,
              () => Get.back());
        }
      },
    );
  }

  /// Formats a phone number to the standard Syrian international format (+963...).
  String _formatSyrianPhoneNumber(String input) {
    String digitsOnly = input.replaceAll(RegExp(r'\D'), '');

    if (digitsOnly.startsWith('09') && digitsOnly.length == 10) {
      return '963${digitsOnly.substring(1)}';
    }
    if (digitsOnly.length == 9 && digitsOnly.startsWith('9')) {
      return '963$digitsOnly';
    }
    return input; // Fallback for unrecognized formats
  }

  String normalizeSyrianPhone(String input) {
    String phone = input.trim();

    // احذف كل شيء غير أرقام
    phone = phone.replaceAll(RegExp(r'[^0-9]'), '');

    // إذا يبدأ بـ 0 → احذفها
    if (phone.startsWith('0')) {
      phone = phone.substring(1);
    }

    // إذا يبدأ بـ 963 مكررة → احذف التكرار
    while (phone.startsWith('963963')) {
      phone = phone.substring(3);
    }

    // إذا يبدأ بـ 963 ولكن داخله كمان 963 → خليه مرة واحدة فقط
    if (phone.startsWith('963') && phone.length > 12) {
      phone = phone.substring(phone.length - 9); // آخر 9 أرقام
    }

    // الآن إذا كان بلا 963 → أضفها
    if (!phone.startsWith('963')) {
      phone = '963' + phone;
    }

    return phone;
  }

  /// Sends an invitation to a potential new driver.
  void sendInvite() async {
    if (invitePhoneController.text.isEmpty) {
      mySnackeBarError('Please enter a phone number'.tr);
      return;
    }
    // Format Syrian phone number: remove leading 0 and add +963
    String formattedPhoneNumber =
        normalizeSyrianPhone(invitePhoneController.text);
    if (formattedPhoneNumber.length != 12) {
      mySnackeBarError('Please enter a correct phone'.tr);
      return;
    }

    var response = await CRUD().post(link: AppLink.addInviteDriver, payload: {
      "driverId": box.read(BoxName.driverID),
      "inviterDriverPhone": formattedPhoneNumber,
    });

    if (response != 'failure') {
      var d = (response);
      mySnackbarSuccess('Invite sent successfully'.tr);
      String message = '${'*Intaleq DRIVER CODE*'.tr}\n\n'
          '${"Use this code in registration".tr}\n'
          '${"To get a gift for both".tr}\n\n'
          '${"The period of this code is 1 hour".tr}\n\n'
          '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n'
          '_*${d['message']['inviteCode'].toString()}*_\n\n'
          '${"Install our app:".tr}\n'
          '*Android:* https://play.google.com/store/apps/details?id=com.intaleq_driver \n\n\n'
          '*iOS:* https://apps.apple.com/st/app/intaleq-driver/id6482995159';

      launchCommunication('whatsapp', formattedPhoneNumber, message);
      invitePhoneController.clear();
    } else {
      mySnackeBarError("Invite code already used".tr);
    }
  }

  /// Sends an invitation to a potential new passenger.
  void sendInviteToPassenger() async {
    if (invitePhoneController.text.isEmpty) {
      mySnackeBarError('Please enter a phone number'.tr);
      return;
    }

    // Format Syrian phone number: remove leading 0 and add +963
    String formattedPhoneNumber = invitePhoneController.text.trim();
    if (formattedPhoneNumber.startsWith('0')) {
      formattedPhoneNumber = formattedPhoneNumber.substring(1);
    }
    formattedPhoneNumber = '+963$formattedPhoneNumber';

    if (formattedPhoneNumber.length < 12) {
      // +963 + 9 digits = 12+
      mySnackeBarError('Please enter a correct phone'.tr);
      return;
    }

    var response = await CRUD().post(
      link: AppLink.addInvitationPassenger,
      payload: {
        "driverId": box.read(BoxName.driverID),
        "inviterPassengerPhone": formattedPhoneNumber,
      },
    );

    if (response != 'failure') {
      var d = response;
      mySnackbarSuccess('Invite sent successfully'.tr);

      String message = '${'*Intaleq APP CODE*'.tr}\n\n'
          '${"Use this code in registration".tr}\n\n'
          '${"To get a gift for both".tr}\n\n'
          '${"The period of this code is 1 hour".tr}\n\n'
          '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n'
          '_*${d['message']['inviteCode'].toString()}*_\n\n'
          '${"Install our app:".tr}\n'
          '*Android:* https://play.google.com/store/apps/details?id=com.Intaleq.intaleq\n\n\n'
          '*iOS:* https://apps.apple.com/st/app/intaleq-rider/id6748075179';

      launchCommunication('whatsapp', formattedPhoneNumber, message);
      invitePhoneController.clear();
    } else {
      mySnackeBarError("Invite code already used".tr);
    }
  }
}

class PassengerStats {
  final int totalInvites;
  final int activeUsers;
  final double totalEarnings;

  PassengerStats({
    this.totalInvites = 0,
    this.activeUsers = 0,
    this.totalEarnings = 0.0,
  });
}
