import 'dart:convert';

import 'package:Intaleq/constant/box_name.dart';
import 'package:Intaleq/constant/colors.dart';
import 'package:Intaleq/constant/links.dart';
import 'package:Intaleq/controller/functions/crud.dart';
import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:get/get.dart';
import 'package:share_plus/share_plus.dart';

import '../../../main.dart';
import '../../../print.dart';
import '../../../views/widgets/error_snakbar.dart';
import '../../../views/widgets/mydialoug.dart';
import '../../functions/launch.dart';
import '../../notification/notification_captain_controller.dart';
import '../../payment/payment_controller.dart';

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

  int selectedTab = 0;
  PassengerStats passengerStats = PassengerStats();

  List<Contact> contacts = <Contact>[];
  RxList<Map<String, dynamic>> contactMaps = <Map<String, dynamic>>[].obs;

  @override
  void onInit() {
    super.onInit();
    // It's good practice to fetch initial data in onInit or onReady
    // fetchDriverStats();
    // fetchDriverStatsPassengers();
  }

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

  // --- Sharing Methods ---

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

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

  // --- Data Fetching ---

  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) {
      Log.print("Error fetching driver stats: $e");
    }
  }

  void fetchDriverStatsPassengers() async {
    try {
      var response = await CRUD()
          .get(link: AppLink.getDriverInvitationToPassengers, payload: {
        "driverId": box.read(BoxName.passengerID),
      });
      if (response != 'failure') {
        var data = jsonDecode(response);
        driverInvitationDataToPassengers = data['message'];
        update();
      }
    } catch (e) {
      Log.print("Error fetching passenger stats: $e");
    }
  }

  // --- Contact Handling ---

  /// **IMPROVEMENT**: This function now filters out contacts without any phone numbers.
  /// This is the fix for the `RangeError` you were seeing, which happened when the UI
  /// tried to access the first phone number of a contact that had none.
  Future<void> pickContacts() async {
    try {
      if (await FlutterContacts.requestPermission(readonly: true)) {
        final List<Contact> allContacts =
            await FlutterContacts.getContacts(withProperties: true);
        final int totalContactsOnDevice = allContacts.length;

        // **FIX**: Filter contacts to only include those with at least one phone number.
        contacts = allContacts.where((c) => c.phones.isNotEmpty).toList();
        final int contactsWithPhones = contacts.length;

        if (contactsWithPhones > 0) {
          Log.print('Found $contactsWithPhones contacts with phone numbers.');
          contactMaps.value = contacts.map((contact) {
            return {
              'name': contact.displayName,
              'phones': contact.phones.map((p) => p.number).toList(),
              'emails': contact.emails.map((e) => e.address).toList(),
            };
          }).toList();
          update();

          // **IMPROVEMENT**: Provide feedback if some contacts were filtered out.
          if (contactsWithPhones < totalContactsOnDevice) {
            Get.snackbar('Contacts Loaded'.tr,
                '${'Showing'.tr} $contactsWithPhones ${'of'.tr} $totalContactsOnDevice ${'contacts. Others were hidden because they don\'t have a phone number.'.tr}',
                snackPosition: SnackPosition.BOTTOM);
          }
        } else {
          Get.snackbar('No contacts found'.tr,
              'No contacts with phone numbers were found on your device.'.tr);
        }
      } else {
        Get.snackbar('Permission denied'.tr,
            'Contact permission is required to pick contacts'.tr);
      }
    } catch (e) {
      Log.print('Error picking contacts: $e');
      Get.snackbar(
          'Error'.tr, 'An error occurred while picking contacts: $e'.tr);
    }
  }

  void selectPhone(String phone) {
    invitePhoneController.text = phone;
    update();
    Get.back();
  }

  /// **IMPROVEMENT**: A new robust function to format phone numbers specifically for Syria (+963).
  /// It handles various user inputs gracefully to produce a standardized international format.
  String _formatSyrianPhoneNumber(String phone) {
    // 1. Remove all non-digit characters to clean the input.
    String digitsOnly = phone.replaceAll(RegExp(r'\D'), '');

    // 2. If it already starts with the country code, we assume it's correct.
    if (digitsOnly.startsWith('963')) {
      return '$digitsOnly';
    }

    // 3. If it starts with '09' (common local format), remove the leading '0'.
    if (digitsOnly.startsWith('09')) {
      digitsOnly = digitsOnly.substring(1);
    }

    // 4. Prepend the Syrian country code.
    return '963$digitsOnly';
  }

  /// **IMPROVEMENT**: This method now uses the new phone formatting logic and
  /// sends a much-improved, user-friendly WhatsApp message.
  void sendInviteToPassenger() async {
    if (invitePhoneController.text.isEmpty ||
        invitePhoneController.text.length < 9) {
      mySnackeBarError('Please enter a correct phone'.tr);
      return;
    }

    try {
      // Use the new formatting function to ensure the number is correct.
      String formattedPhoneNumber =
          _formatSyrianPhoneNumber(invitePhoneController.text);

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

      if (response != 'failure') {
        var d = response;
        Get.snackbar('Success'.tr, 'Invite sent successfully'.tr,
            backgroundColor: Colors.green, colorText: Colors.white);

        String expirationTime = d['message']['expirationTime'].toString();
        String inviteCode = d['message']['inviteCode'].toString();

        // New and improved WhatsApp message for better user engagement.
        String message =
            "👋 ${'Hello! I\'m inviting you to try Intaleq.'.tr}\n\n"
            "🎁 ${'Use my invitation code to get a special gift on your first ride!'.tr}\n\n"
            "${'Your personal invitation code is:'.tr}\n"
            "*$inviteCode*\n\n"
            "⏳ ${'Be sure to use it quickly! This code expires at'.tr} *$expirationTime*.\n\n"
            "📲 ${'Download the app now:'.tr}\n"
            "• *Android:* https://play.google.com/store/apps/details?id=com.Intaleq.intaleq\n"
            "• *iOS:* https://apps.apple.com/st/app/intaleq-rider/id6748075179\n\n"
            "${'See you on the road!'.tr} 🚗";

        launchCommunication('whatsapp', formattedPhoneNumber, message);
        invitePhoneController.clear();
        update();
      } else {
        Get.snackbar(
            'Error'.tr, "This phone number has already been invited.".tr,
            backgroundColor: AppColor.redColor,
            duration: const Duration(seconds: 4));
      }
    } catch (e) {
      Log.print("Error sending invite: $e");
      Get.snackbar(
          'Error'.tr, 'An unexpected error occurred. Please try again.'.tr,
          backgroundColor: AppColor.redColor);
    }
  }

  // This function is dependent on the `pickContacts` method filtering out contacts without phones.
  savePhoneToServer() async {
    for (var contactMap in contactMaps) {
      // The `pickContacts` function ensures the 'phones' list is not empty here.
      var phones = contactMap['phones'] as List<String>;
      var res = await CRUD().post(link: AppLink.savePhones, payload: {
        "name": contactMap['name'] ?? 'No Name',
        "phones": phones.first, // Safely access the first phone number
        "phones2": phones.join(', '),
      });
      if (res == 'failure') {
        Log.print('Failed to save contact: ${contactMap['name']}');
      }
    }
  }

  void onSelectPassengerInvitation(int index) async {
    try {
      final invitation = driverInvitationDataToPassengers[index];
      final tripCount =
          int.tryParse(invitation['countOfInvitDriver'].toString()) ?? 0;
      final passengerName = invitation['passengerName'].toString();
      final isGiftTaken = invitation['isGiftToken'].toString() == '1';

      if (tripCount >= 2) {
        // Gift can be claimed
        if (!isGiftTaken) {
          MyDialog().getDialog(
            'You deserve the gift'.tr,
            '${'Claim your 20 LE gift for inviting'.tr} $passengerName!',
            () async {
              Get.back(); // Close dialog first
              await Get.find<PaymentController>().addPassengersWallet('20');
              await CRUD().post(
                link: AppLink.updatePassengerGift,
                payload: {'id': invitation['id']},
              );
              NotificationCaptainController().addNotificationCaptain(
                invitation['passengerInviterId'].toString(),
                "You have got a gift for invitation".tr,
                '${"You have earned 20".tr} ${'LE'}',
                false,
              );
              fetchDriverStatsPassengers(); // Refresh list
            },
          );
        } else {
          MyDialog().getDialog(
            "Gift Already Claimed".tr,
            "You have already received your gift for inviting $passengerName."
                .tr,
            () => Get.back(),
          );
        }
      } else {
        // Gift not yet earned
        MyDialog().getDialog(
          '${'Keep it up!'.tr}',
          '$passengerName ${'has completed'.tr} $tripCount / 2 ${'trips'.tr}. ${"You can claim your gift once they complete 2 trips.".tr}',
          () => Get.back(),
        );
      }
    } catch (e) {
      Log.print("Error in onSelectPassengerInvitation: $e");
    }
  }
}

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

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