import 'dart:convert';
import 'dart:io';
import 'package:comwell_key_app/hotel_information/models/hotel.dart';
import 'package:comwell_key_app/domain/models/housekeeping.dart';
import 'package:comwell_key_app/domain/models/notification_permission.dart';
import 'package:comwell_key_app/presentation/screens/pregistration/prereg_request_model.dart';
import 'package:comwell_key_app/services/http_client.dart';
import 'package:comwell_key_app/services/models/booking_dto.dart';
import 'package:comwell_key_app/services/models/simple_user_dto.dart';
import 'package:comwell_key_app/services/models/user_dto.dart';
import 'package:comwell_key_app/services/utils/api_endpoints.dart';
import 'package:comwell_key_app/up_sales/models/addon_list.dart';
import 'package:comwell_key_app/up_sales/models/dto/up_sales_dto.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:package_info_plus/package_info_plus.dart';

class Api {
  final ComwellHttpClient _client = locator.get();

  Dio get dio => _client.dio;

  Api();

  // Get current locale globally
  Locale get _currentLocale {
    final navigatorKey = locator<GlobalKey<NavigatorState>>();
    final languageCode = navigatorKey.currentContext!.strings.localeName;
    final countryCode = switch (languageCode) {
      'en' => 'US',
      'da' => 'DK',
      _ => 'DK',
    };
    return Locale(languageCode, countryCode);
  }

  Future<Response<dynamic>> logout() async {
    return await dio.post(ApiEndpoints.logout);
  }

  Future<List<BookingDTO>> fetchPastBookingsForUser() async {
    final body = {
      "skip": 0,
      "limit": 100,
    };
    final json = jsonEncode(body);
    final response = await dio.get<List<dynamic>>(ApiEndpoints.getPastBookings, data: json);
    return response.data!.map((e) => BookingDTO.fromJson(e as Json)).toList();
  }

  Future<List<BookingDTO>> fetchCancelledBookingsForUser() async {
    final body = {
      "skip": 0,
      "limit": 100,
    };
    final json = jsonEncode(body);
    final response = await dio.get<List<dynamic>>(ApiEndpoints.getCancelledBookings, data: json);
    return response.data!.map((e) => BookingDTO.fromJson(e as Json)).toList();
  }

  Future<List<BookingDTO>> fetchCurrentBookingsForUser() async {
    final body = {
      "skip": 0,
      "limit": 100,
    };
    final json = jsonEncode(body);
    final response = await dio.get<List<dynamic>>(ApiEndpoints.getCurrentBookings, data: json);

    return response.data!.map((e) => BookingDTO.fromJson(e as Json)).toList();
  }

  Future<Response<dynamic>> fetchProfileSettings() async {
    final response = await dio.get<dynamic>(ApiEndpoints.getGuestProfile);
    return response;
  }

  Future<void> deleteProfile() {
    return dio.delete<void>(ApiEndpoints.deleteGuest);
  }

  Future<Response<dynamic>> signupForComwellClub() async {
    final response = await dio.post<dynamic>(ApiEndpoints.clubSignup);
    return response;
  }

  Future<Response<dynamic>> preArrival(PreregRequestDto request) async {
    final json = jsonEncode(request);
    debugPrint("json: $json");
    final response = await dio.post<dynamic>(ApiEndpoints.preArrivalByToken, data: json);
    return response;
  }

  Future<Response<dynamic>> getNotificationPermissions() async {
    final response = await dio.get<dynamic>(
      '${ApiEndpoints.communicationPreference}?permissionAreas=club',
    );

    return response;
  }

  Future<BookingDTO> findBookingByConfirmationId(String confirmationId, String lastName) async {
    final body = {
      "confirmationNumber": confirmationId,
      "lastName": lastName,
    };

    final data = jsonEncode(body);
    final response = await dio.post<Json>(ApiEndpoints.findBookingByConfirmationId, data: data);
    return BookingDTO.fromJson(response.data!);
  }

  Future<dynamic> updateNotificationPreferences(
    Iterable<NotificationPermission> notificationPermissions,
  ) {
    final permissions = {
      for (var permission in notificationPermissions) permission.code.toString(): permission.given,
    };
    final simpleUserDto = SimpleUserDto(permissions: permissions);
    return updateUser(simpleUserDto);
  }

  Future<dynamic> updateUser(SimpleUserDto updatedUser) {
    final json = jsonEncode(updatedUser);
    debugPrint("Updated user: $json");
    final response = dio.put<void>(
      ApiEndpoints.updateGuestData,
      data: json,
    );
    return response;
  }

  Future<dynamic> getHotelInfo(String hotelCode) async {
    final cultureString = _currentLocale.toString().replaceAll('_', '-');
    final url = '${ApiEndpoints.getHotelInfo}?hotelCode=$hotelCode&culture=$cultureString';
    final response = await dio.get<Json>(url);
    return response;
  }

  Future<Json?> checkIn(String confirmationNumber) async {
    final body = {
      "confirmationNumber": confirmationNumber,
    };
    final data = jsonEncode(body);

    final response = await dio.post<Json>(ApiEndpoints.checkIn, data: data);

    return response.data;
  }

  Future<Json?> checkOut(String confirmationNumber) async {
    final body = {
      "confirmationNumber": confirmationNumber,
    };
    final data = jsonEncode(body);
    final response = await dio.post<Json>(ApiEndpoints.checkOut, data: data);

    return response.data;
  }

  Future<Json?> orderHousekeeping(Housekeeping housekeeping) async {
    final body = {
      "hotelCode": housekeeping.hotelCode,
      "roomNumber": housekeeping.roomNumber,
      "cleaning": housekeeping.cleaning,
      "soap": housekeeping.soap,
      "towels": housekeeping.towels,
      "trash": housekeeping.trash,
      "refill": housekeeping.refill,
    };
    final data = jsonEncode(body);
    final response = await dio.post<Json>(ApiEndpoints.orderHousekeeping, data: data);
    return response.data;
  }

  Future<void> sendContact(String hotelCode) async {}

  Future<void> bookSpa(Hotel hotel) async {
    await Future<void>.delayed(const Duration(seconds: 2));
    // TODO implement
  }

  Future<String> createEndpointRegistration() async {
    final response = await dio.post<String>(ApiEndpoints.createEndpointRegistration);
    final json = jsonDecode(response.data!) as Map<String, dynamic>;
    return json["invitationCode"]! as String;
  }

  Future<void> provisionKey(String confirmationNumber, String hotelCode) async {
    await dio.post<void>(
      ApiEndpoints.provisionKey,
      data: {'confirmationNumber': confirmationNumber, 'hotelCode': hotelCode},
    );
  }

  Future<BookingDTO?> getBookingDetails(String confirmationNumber, String hotelCode) async {
    final uri = Uri.parse(ApiEndpoints.getBookingDetails).replace(
      queryParameters: {
        'confirmationNumber': confirmationNumber,
        'hotelCode': hotelCode,
      },
    );
    final response = await dio.get<Json>(uri.toString());
    debugPrint("Response: ${response.data}");
    return BookingDTO.fromJson(response.data!);
  }

  Future<Json> postRoomSelection(String confirmationNumber, String userId) async {
    final body = {
      "confirmationNumber": confirmationNumber,
      "userId": userId,
    };
    final data = jsonEncode(body);
    final response = await dio.post<Json>('ApiEndpoints.roomSelection', data: data);
    return response.data!;
  }

  Future<UpSalesDTO> fetchUpSales(String confirmationNumber, String hotelCode) async {
    final body = {
      "confirmationNumber": confirmationNumber,
      "property": hotelCode,
      "culture": _currentLocale.toString().replaceAll('_', '-'),
    };
    final data = jsonEncode(body);
    final response = await dio.post<Json>(ApiEndpoints.upSales, data: data);
    return UpSalesDTO.fromJson(response.data!);
  }

  Future<void> addUpSalesToBooking(
    String confirmationNumber,
    String hotelCode,
    String roomType,
    List<AddOnList> selectedUpSales,
  ) async {
    final body = {
      "confirmationNumber": confirmationNumber,
      "property": hotelCode,
      "roomType": roomType,
      "addOnList": selectedUpSales,
    };
    final data = jsonEncode(body);
    await dio.post<void>(ApiEndpoints.addUpSalesToBooking, data: data);
    return;
  }

  Future<void> removeGuestsFromBooking(
    String confirmationNumber,
    String hotelCode,
    int guestId,
  ) async {
    final body = {
      "hotelCode": hotelCode,
      "confirmationNumber": confirmationNumber,
      "personId": guestId,
    };
    final data = jsonEncode(body);
    debugPrint("Data: $data");
    await dio.post<void>(ApiEndpoints.removeGuestsFromBooking, data: data);
  }

  Future<String> createRoomSharingLink(
    String confirmationNumber,
    String hotelCode,
    int sharingType,
  ) async {
    final body = {
      "confirmationNumber": confirmationNumber,
      "hotelCode": hotelCode,
      "sharingType": sharingType,
    };
    final data = jsonEncode(body);
    final response = await dio.post<String>(ApiEndpoints.createRoomSharingLink, data: data);
    debugPrint("Response: $response");
    return response.data!;
  }

  Future<BookingDTO> consumeRoomSharingLink(String sharingId, String hotelCode) async {
    final uri = Uri.parse(ApiEndpoints.consumeRoomSharingLink).replace(
      queryParameters: {
        'sharingId': sharingId,
        'hotelCode': hotelCode,
      },
    );
    final response = await dio.get<Json>(uri.toString());
    return BookingDTO.fromJson(response.data!);
  }

  Future<void> registerDeviceAndProfileSymplify(String token) async {
    final symplifyUrl = dotenv.env['SYMPLIFY_URL'];
    final apiKey = dotenv.env['SYMPLIFY_API_KEY'];
    final customerId = dotenv.env['SYMPLIFY_CUSTOMER_ID'];
    final packageInfo = await PackageInfo.fromPlatform();
    final packageName = packageInfo.packageName;

    debugPrint('Package name: $packageName');

    //App type 6 is Firebase
    //https://apidocs.symplify.com/#233ad620-28d7-4d19-b394-cfcac0ed2a49
    final profileResponse = await fetchProfileSettings();
    final profileData = profileResponse.data as Json;
    final profile = UserDto.fromJson(profileData);
    String emailAddress = '';
    String firstName = '';
    String lastName = '';
    if (Platform.isIOS) {
      emailAddress = '${profile.email}IOS-test';
      firstName = '${profile.firstName}IOS-test';
      lastName = '${profile.lastName}IOS-test';
    } else {
      emailAddress = '${profile.email}Android-test';
      firstName = '${profile.firstName}Android-test';
      lastName = '${profile.lastName}Android-test';
    }
    final body = {
      "originalId": emailAddress,
      "firstName": firstName,
      "lastName": lastName,
      "emailAddress": emailAddress,
      "deviceInfo": [
        {
          "devicetoken": token,
          "appType": "6",
        },
      ],
    };
    final data = jsonEncode(body);
    await dio.put<void>(
      '$symplifyUrl/$customerId/apps/$packageName/devices',
      data: data,
      options: Options(
        headers: {
          'X-Carma-Authentication-Token': apiKey,
          'Content-Type': 'application/json',
        },
      ),
    );
    return;
  }
}