import 'package:comwell_key_app/domain/models/app_error.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/presentation/screens/pregistration/cubit/preregistration_state.dart';
import 'package:comwell_key_app/presentation/screens/pregistration/prereg_request_model.dart';
import 'package:comwell_key_app/domain/repositories/pregistration_repository.dart';
import 'package:comwell_key_app/presentation/screens/pregistration/utils/utils.dart';
import 'package:comwell_key_app/presentation/base/base_cubit.dart';
import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/domain/models/address.dart';
import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/tracking/models/analytics_event_item.dart';
import 'package:comwell_key_app/up_sales/models/addon_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade.dart';
import 'package:comwell_key_app/up_sales/models/upgrade.dart';
import 'package:comwell_key_app/up_sales/up_sales_repository.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:comwell_key_app/utils/phone_utils.dart';
import 'package:country_code_picker/country_code_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:payment_plugin/domain/models/stored_payment_method.dart';

class PreregistrationCubit extends BaseCubit<PreregistrationState> {
  final _profileRepository = locator<ProfileRepository>();
  final _profileSettingsRepository = locator<ProfileSettingsRepository>();
  final _tracking = locator<ComwellTracking>();
  final _preregistrationRepository = locator<PreregistrationRepository>();
  final _upSalesRepository = locator<UpSalesRepository>();

  final Booking booking;

  final pageController = PageController();
  final addressTextController = TextEditingController();
  final postalCodeTextController = TextEditingController();
  final cityTextController = TextEditingController();
  final firstNameTextController = TextEditingController();
  final lastNameTextController = TextEditingController();
  final emailTextController = TextEditingController();
  final phoneNumberTextController = TextEditingController();
  final documentNumberTextController = TextEditingController();
  final commentTextController = TextEditingController();

  CountryCode? countryCode;

  String? phoneNumber;

  final List<String> favoriteCountries = ['DK', 'SE', 'NO', 'FI'];

  IdType selectedDocumentType = IdType.passport;
  String selectedCountry = '';
  String selectedNationality = '';
  PreregistrationPage get currentPage =>
      PreregistrationPage.fromIndex(pageController.page?.toInt() ?? 0);
  bool _isAnimating = false;

  PreregistrationCubit({required this.booking}) : super(const PreregistrationState()) {
    init();
  }

  void init() async {
    setupListeners();
    safeEmit(state.copyWith(isLoading: true));
    try {
      final user = await _profileRepository.fetchProfileSettings();
      addressTextController.text = user.address.street;
      postalCodeTextController.text = user.address.zipCode;
      cityTextController.text = user.address.city;

      selectedNationality = user.nationality != '' ? user.nationality : 'DK';
      selectedCountry = user.nationality != '' ? user.nationality : 'DK';

      countryCode = getCountryCodeFromPhoneNumber(user.phoneNumber).$1;
      phoneNumber = getCountryCodeFromPhoneNumber(user.phoneNumber).$2;

      firstNameTextController.text = user.firstName;
      lastNameTextController.text = user.lastName;
      emailTextController.text = user.email;
      phoneNumberTextController.text = phoneNumber ?? '';

      safeEmit(state.copyWith(user: user));

      final upSales = await _upSalesRepository.getRemoteUpSales(
        booking.confirmationNumber,
        booking.hotelCode,
      );

      safeEmit(
        state.copyWith(
          isLoading: false,
          availableRoomUpgrades: upSales.roomUpgrades,
          addOnUpgrades: upSales.addOnUpgrades,
          selectedCountry: countryCode?.code ?? 'DK',
          countryCode: countryCode,
          phoneNumber: phoneNumber,
        ),
      );
    } catch (e, st) {
      logError(e, st);
      safeEmit(state.copyWith(isLoading: false));
    }
  }

  void setupListeners() {
    phoneNumberTextController.addListener(() {
      if (state.missingInformation) {
        safeEmit(state.copyWith(missingInformation: false));
      } else {
        safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
      }
    });

    addressTextController.addListener(() {
      if (state.missingInformation) {
        safeEmit(state.copyWith(missingInformation: false));
      } else {
        safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
      }
    });

    postalCodeTextController.addListener(() {
      if (state.missingInformation) {
        safeEmit(state.copyWith(missingInformation: false));
      } else {
        safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
      }
    });

    cityTextController.addListener(() {
      if (state.missingInformation) {
        safeEmit(state.copyWith(missingInformation: false));
      } else {
        safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
      }
    });
  }

  void onDocumentTypeSelected(IdType documentType) {
    selectedDocumentType = documentType;
    safeEmit(state.copyWith(selectedDocumentType: documentType));
  }

  void onAddressContinueClicked() {
    if (isAddressValid && isCityValid && isPostalCodeValid) {
      final updatedUser = state.user!.copyWith(
        address: Address(
          street: addressTextController.text,
          zipCode: postalCodeTextController.text,
          city: cityTextController.text,
          country: state.selectedCountry,
        ),
      );

      safeEmit(state.copyWith(user: updatedUser));
      _navigateNextPage();
    } else {
      safeEmit(state.copyWith(missingInformation: true));
    }
  }

  void onProfileContinueClicked() {
    if (isFirstNameValid && isLastNameValid && isPhoneNumberValid && isBirthDateValid) {
      final phoneNumber = concatCountryCodeAndPhoneNumber(
        countryCode!,
        phoneNumberTextController.text,
      );
      final updatedUser = state.user!.copyWith(
        firstName: firstNameTextController.text,
        lastName: lastNameTextController.text,
        phoneNumber: phoneNumber,
        nationality: selectedNationality,
      );
      safeEmit(state.copyWith(user: updatedUser));

      _navigateNextPage();
    } else {
      safeEmit(state.copyWith(missingInformation: true));
    }
  }

  void onUpSalesContinueClicked() {
    _navigateNextPage();
  }

  void onContinueClicked(BuildContext context) {
    if (_isAnimating) return;
    switch (currentPage) {
      case PreregistrationPage.profile:
        onProfileContinueClicked();
        break;
      case PreregistrationPage.address:
        onAddressContinueClicked();
        break;
      case PreregistrationPage.upSales:
        onUpSalesContinueClicked();
        break;
      case PreregistrationPage.confirmation:
        _onConfirmPressed(context);
        break;
    }
  }

  void onPaymentMethodSelected(StoredPaymentMethod paymentMethod) {
    safeEmit(
      state.copyWith(
        selectedPaymentMethod: paymentMethod,
        missingInformation: false,
      ),
    );
  }

  void addToCart() {
    final analyticsEventItem = AnalyticsEventItem(
      hotelName: booking.hotelName,
      currency: "DKK",
      value: extrasTotalPrice,
      placement: "pre-registration",
      items: selectedAddOnUpgrades.map((e) => e.name).toList(),
      itemIds: selectedAddOnUpgrades.map((e) => e.id).toList(),
      bookingReference: booking.confirmationNumber,
    );
    _tracking.trackAddToCart(analyticsEventItem);
  }

  void _onConfirmPressed(BuildContext context) async {
    safeEmit(state.copyWith(isLoading: true));
    try {
      // Build the PreregRequestModel with all required fields
      final String? sendIdType = isFavoriteCountry ? null : selectedDocumentType.code;
      final String? sendRoomType = state.selectedRoomUpgrade.isNotEmpty
          ? state.selectedRoomUpgrade
          : null;
      final List<AddOnListDto>? sendAddOnList = numOfExtras > 0
          ? selectedAddOnUpgrades
                .map((e) => AddOnListDto(itemCode: e.id, quantity: e.quantity))
                .toList()
          : null;
      final String? sendArrivalTime = state.servingTime.toString().isNotEmpty
          ? state.servingTime?.toString()
          : null;

      final preregRequest = PreregRequestDto(
        firstName: state.user!.firstName,
        lastName: state.user!.lastName,
        email: state.user!.email,
        phoneNumber: state.user!.phoneNumber,
        birthDay: state.user!.birthDate!.toIso8601String(),
        address: state.user!.address.street,
        zipCode: state.user!.address.zipCode,
        city: state.user!.address.city,
        country: state.user!.address.country,
        nationality: state.user!.nationality,
        confirmationNumber: booking.confirmationNumber,
        idType: sendIdType,
        idNumber: documentNumberTextController.text,
        idCountry: selectedNationality,
        arrivalTime: sendArrivalTime,
        comment: commentTextController.text,
        hotelCode: booking.hotelCode,
        roomType: sendRoomType,
        addOnList: sendAddOnList,
      );

      await _profileSettingsRepository.updateUser(state.user!);
      final preRegResponse = await _preregistrationRepository.createPreregistration(preregRequest);

      if (preRegResponse != null) {
        Future.delayed(const Duration(seconds: 3), () {
          safeEmit(state.copyWith(isLoading: false));
          if (!context.mounted) return;
          context.pop(preRegResponse);
        });
      } else {
        safeEmit(state.copyWith(error: AppError.unknown('Pre-registration failed'), isLoading: false));
        if (!context.mounted) return;
        context.pop(null);
      }
    } catch (e, st) {
      logError(e, st);
      safeEmit(state.copyWith(error: AppError.unknown(e.toString()), isLoading: false));
    }
  }

  void onEditProfileClicked() {
    _navigateTo(PreregistrationPage.profile);
  }

  void onEditAddressClicked() {
    _navigateTo(PreregistrationPage.address);
  }

  void onEditExtrasClicked() {
    _navigateTo(PreregistrationPage.upSales);
  }

  void onPhoneNumberChanged(String phoneNumber) {
    phoneNumberTextController.text = phoneNumber;
    safeEmit(state.copyWith(isPhoneNumberValid: isPhoneNumberValid));
  }

  void onCountryCodeSelected(CountryCode country) {
    countryCode = country;
    safeEmit(state.copyWith(countryCode: country, selectedCountry: country.code ?? ''));
  }

  void onNationalitySelected(String nationality) {
    selectedNationality = nationality;
    safeEmit(state.copyWith(selectedNationality: selectedNationality));
  }

  void onSelectedCountrySelected(String country) {
    selectedCountry = country;
    safeEmit(state.copyWith(selectedCountry: country));
  }

  Future<void> onBirthDateSelected(DateTime date) async {
    final updatedUser = state.user!.copyWith(birthDate: date);
    safeEmit(state.copyWith(user: updatedUser));
  }

  bool onBackClicked() {
    if (_isAnimating) return true;
    final hasPage = pageController.page != null;
    if (hasPage && pageController.page! >= 1.0) {
      _navigatePreviousPage();
      return true;
    }
    return false;
  }

  void _navigateTo(PreregistrationPage page) async {
    if (_isAnimating) return;
    _isAnimating = true;
    await pageController.animateToPage(
      page.index,
      duration: const Duration(milliseconds: 500),
      curve: Curves.fastOutSlowIn,
    );
    safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
    _isAnimating = false;
  }

  void _navigateNextPage() async {
    if (_isAnimating) return;
    _isAnimating = true;
    await pageController.nextPage(
      duration: const Duration(milliseconds: 500),
      curve: Curves.fastOutSlowIn,
    );
    safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
    _isAnimating = false;
  }

  void _navigatePreviousPage() async {
    if (_isAnimating) return;
    _isAnimating = true;
    await pageController.previousPage(
      duration: const Duration(milliseconds: 500),
      curve: Curves.fastOutSlowIn,
    );
    safeEmit(state.copyWith(forceUpdate: !state.forceUpdate));
    _isAnimating = false;
  }

  int get extrasTotalPrice {
    //This is the total price of the selected up sales and the price of the selected
    //room upgrade if it is selected

    return selectedAddOnUpgrades.fold(0, (sum, upgrade) => sum + upgrade.price * upgrade.quantity) +
        (state.selectedRoomUpgrade.isNotEmpty
            ? state.availableRoomUpgrades.firstWhere((e) => e.id == state.selectedRoomUpgrade).price
            : 0);
  }

  int get numOfExtras =>
      selectedAddOnUpgrades.fold(0, (sum, upgrade) => sum + upgrade.quantity) +
      (state.selectedRoomUpgrade.isNotEmpty ? 1 : 0);

  List<AddOnUpgrade> get otherUpgrades {
    final selectedUpgrades = state.addOnUpgrades.where((upgrade) => !upgrade.isService).toList();
    return selectedUpgrades;
  }

  List<AddOnUpgrade> get selectedAddOnUpgrades {
    final selectedUpgrades = state.addOnUpgrades.where((upgrade) => upgrade.isAddedToCart).toList();
    return selectedUpgrades;
  }

  @override
  Future<void> close() {
    addressTextController.dispose();
    postalCodeTextController.dispose();
    cityTextController.dispose();
    pageController.dispose();
    firstNameTextController.dispose();
    lastNameTextController.dispose();
    emailTextController.dispose();
    phoneNumberTextController.dispose();
    documentNumberTextController.dispose();
    commentTextController.dispose();
    return super.close();
  }

  bool get isAddressValid => addressTextController.text.isNotEmpty;

  bool get isPostalCodeValid => postalCodeTextController.text.isNotEmpty;

  bool get isCityValid => cityTextController.text.isNotEmpty;

  bool get isDocumentNumberValid => documentNumberTextController.text.isNotEmpty;

  bool get isPhoneNumberValid =>
      phoneNumberTextController.text.length >= 7 && phoneNumberTextController.text.length < 16;

  bool get isFirstNameValid => firstNameTextController.text.isNotEmpty;

  bool get isLastNameValid => lastNameTextController.text.isNotEmpty;

  bool get isBirthDateValid => state.user!.birthDate!.isBefore(validBirthDate);

  DateTime get validBirthDate => DateTime.now().subtract(const Duration(days: 365 * 18));

  bool get isFavoriteCountry => favoriteCountries.contains(selectedNationality);

  bool get canContinue {
    int page = pageController.page?.ceil() ?? 0;

    final preregPage = PreregistrationPage.fromIndex(page);

    switch (preregPage) {
      case PreregistrationPage.profile:
        return isFirstNameValid && isLastNameValid && isPhoneNumberValid && isBirthDateValid;
      case PreregistrationPage.address:
        return isAddressValid && isPostalCodeValid && isCityValid;
      case PreregistrationPage.upSales:
        return true;
      case PreregistrationPage.confirmation:
        return state.termsAndConditionsAccepted;
    }
  }

  String buttonText(BuildContext context) {
    int page = pageController.page?.ceil() ?? 0;
    final preregPage = PreregistrationPage.fromIndex(page);
    switch (preregPage) {
      case PreregistrationPage.profile:
        return context.strings.generic_continue;
      case PreregistrationPage.address:
        return context.strings.generic_continue;
      case PreregistrationPage.upSales:
        if (selectedAddOnUpgrades.isEmpty && state.selectedRoomUpgrade.isEmpty) {
          return context.strings.continue_without_up_sales;
        }
        return context.strings.generic_continue;
      case PreregistrationPage.confirmation:
        return context.strings.generic_confirm;
    }
  }

  void onTermsAndConditionsToggled(bool toggle) {
    safeEmit(state.copyWith(termsAndConditionsAccepted: toggle));
  }

  void onServingTimeSelected(TimeOfDay time) {
    safeEmit(state.copyWith(servingTime: time));
  }

  void toggleSelectedUpgrade(Upgrade upgrade) {
    if (upgrade is RoomUpgrade) {
      if (state.selectedRoomUpgrade == upgrade.id) {
        safeEmit(state.copyWith(selectedRoomUpgrade: ''));
      } else {
        safeEmit(state.copyWith(selectedRoomUpgrade: upgrade.id));
      }
    } else if (upgrade is AddOnUpgrade) {
      final bool willSelect = !upgrade.isSelected && upgrade.quantity == 0;
      final updatedUpgrade = upgrade.copyWith(
        isSelected: willSelect,
        quantity: willSelect ? 1 : 0,
      );
      final updatedAddOnUpgrades = state.addOnUpgrades.toList();
      final index = updatedAddOnUpgrades.indexWhere((e) => e.id == updatedUpgrade.id);
      updatedAddOnUpgrades[index] = updatedUpgrade;
      safeEmit(
        state.copyWith(
          addOnUpgrades: updatedAddOnUpgrades,
        ),
      );
    }
  }

  void onContinue() {
    safeEmit(state.copyWith(selected: false));
  }

  void updateAddonUpgradeQuantity(AddOnUpgrade upgrade, int quantity) {
    final updatedUpgrade = upgrade.copyWith(quantity: quantity);
    final updatedAddOnUpgrades = state.addOnUpgrades.toList();
    final index = updatedAddOnUpgrades.indexWhere((e) => e.id == updatedUpgrade.id);
    updatedAddOnUpgrades[index] = updatedUpgrade;
    safeEmit(state.copyWith(addOnUpgrades: updatedAddOnUpgrades));
  }

  String get paymentMethodImage {
    switch (state.selectedPaymentMethod?.brand) {
      case 'mastercard':
        return 'assets/images/master.svg';
      case 'visa':
        return 'assets/images/visa.svg';
      case 'maestro':
        return 'assets/images/maestro.svg';
      default:
        return 'assets/images/visa.png';
    }
  }
}