import 'dart:async';
import 'dart:convert';

import 'package:cookie_jar/cookie_jar.dart';
import 'package:digi_bank/src/app/constants/app_colors.dart';
import 'package:digi_bank/src/app/constants/assets_path/png/png_assets.dart';
import 'package:digi_bank/src/app/routes/routes.dart';
import 'package:digi_bank/src/common/controller/theme/theme_controller.dart';
import 'package:digi_bank/src/network/api/api_path.dart';
import 'package:digi_bank/src/network/response/api_response.dart';
import 'package:digi_bank/src/network/service/token_service.dart';
import 'package:digi_bank/src/utils/extensions/translation_extension.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart' hide Response;

class NetworkService extends GetxService {
  // Properties
  final Dio _dio = Dio();
  final CookieJar cookieJar = CookieJar();
  final String baseUrl = ApiPath.baseUrl;
  late TokenService _tokenService;

  // Lifecycle Methods
  @override
  void onInit() {
    super.onInit();
    _tokenService = Get.find<TokenService>();
    _configureHttpClient();
  }

  // Configuration
  void _configureHttpClient() {
    _dio.options.baseUrl = baseUrl;
    _dio.options.connectTimeout = const Duration(seconds: 10);
    _dio.options.receiveTimeout = const Duration(seconds: 10);
    _dio.options.contentType = 'application/json';
    _dio.options.headers['Accept'] = 'application/json';
    _dio.interceptors.clear();
    _dio.interceptors.add(CookieManager(cookieJar));
    _setupInterceptors();
  }

  // Setup Interceptor
  void _setupInterceptors() {
    _dio.interceptors.clear();
    _dio.interceptors.add(CookieManager(cookieJar));
    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) async {
          String? accessToken = _tokenService.accessToken.value;
          _log('🔑 Token: $accessToken');

          if (accessToken != null && accessToken.isNotEmpty) {
            options.headers['Authorization'] = 'Bearer $accessToken';
          }

          return handler.next(options);
        },
        onError: (DioException error, handler) async {
          if (error.response?.statusCode == 401) {
            _log("Unauthorized. Please login again.");
          }

          return handler.next(error);
        },
      ),
    );
  }

  // Login POST Method
  Future<ApiResponse<Map<String, dynamic>>> login({
    required String email,
    required String password,
  }) async {
    _dio.interceptors.clear();
    _dio.interceptors.add(CookieManager(cookieJar));
    String url = '${_dio.options.baseUrl}${ApiPath.loginEndpoint}';

    _log('📤 Login POST Request URL: $url');
    _log(
      '📦 Login POST Request Body: {"email": $email, "password": $password}',
    );

    try {
      final response = await _dio.post(
        ApiPath.loginEndpoint,
        data: {'email': email, 'password': password},
      );

      _log('✅ Login POST Status Code: ${response.statusCode}');
      _log('✅ Login POST Response: ${response.data}');

      if (response.statusCode == 200) {
        String accessToken = response.data['token'];
        await _tokenService.saveAccessToken(accessToken);
        _setupInterceptors();
        _log('🔑 Token Saved Successfully');
        return ApiResponse.completed(response.data);
      }

      return ApiResponse.error('Login failed.');
    } on DioException catch (e) {
      return _handleDioException(e, "Login POST");
    } catch (e) {
      _log('Login POST Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Registration Step One POST Method
  Future<ApiResponse<Map<String, dynamic>>> registerStepOne({
    required Map<String, dynamic> data,
  }) async {
    _dio.interceptors.clear();
    _dio.interceptors.add(CookieManager(cookieJar));
    String url = '${_dio.options.baseUrl}${ApiPath.registerStepOneEndpoint}';

    _log('📤 Register Step One POST Request URL: $url');
    _log('📦 Register Step One POST Request Body: ${jsonEncode(data)}');

    try {
      final response = await _dio.post(
        ApiPath.registerStepOneEndpoint,
        data: jsonEncode(data),
      );

      _log('✅ Register Step One Status Code: ${response.statusCode}');
      _log('✅ Register Step One Response: ${response.data}');
      _log('🍪 Cookies: ${await cookieJar.loadForRequest(Uri.parse(url))}');

      return _handleResponse(response, "Register Step One");
    } on DioException catch (e) {
      return _handleDioException(e, "Register Step One");
    } catch (e) {
      _log('Register Step One Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Registration Step Two POST Method
  Future<ApiResponse<Map<String, dynamic>>> registerStepTwo({
    required Map<String, dynamic> data,
  }) async {
    String url = '${_dio.options.baseUrl}${ApiPath.registerStepTwoEndpoint}';

    _log('📤 Register Step Two POST Request URL: $url');
    _log('📦 Register Step Two POST Request Body: ${jsonEncode(data)}');
    _log(
      '🍪 Cookies being sent: ${await cookieJar.loadForRequest(Uri.parse(url))}',
    );

    try {
      final response = await _dio.post(
        ApiPath.registerStepTwoEndpoint,
        data: jsonEncode(data),
      );

      _log('✅ Register Step Two Status Code: ${response.statusCode}');
      _log('✅ Register Step Two Response: ${response.data}');

      if (response.statusCode == 200) {
        String accessToken = response.data['token'];
        await _tokenService.saveAccessToken(accessToken);
        _setupInterceptors();
        _log('🔑 Token Saved Successfully');
        return ApiResponse.completed(response.data);
      }

      return ApiResponse.error('Register Step Two failed.');
    } on DioException catch (e) {
      return _handleDioException(e, "Register Step Two");
    } catch (e) {
      _log('Register Step Two Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Interceptor GET Method
  Future<ApiResponse<Map<String, dynamic>>> get({
    required String endpoint,
  }) async {
    String url = '${_dio.options.baseUrl}$endpoint';
    _log('📥 GET Request URL: $url');

    try {
      final response = await _dio.get(endpoint);
      return _handleResponse(response, "GET");
    } on DioException catch (e) {
      return _handleDioException(e, "GET");
    } catch (e) {
      _log('GET Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Interceptor POST Method
  Future<ApiResponse<Map<String, dynamic>>> post({
    required String endpoint,
    Map<String, dynamic>? data,
  }) async {
    String url = '${_dio.options.baseUrl}$endpoint';
    _log('📤 POST Request URL: $url');

    if (data != null) {
      _log('📦 POST Request Body: ${jsonEncode(data)}');
    } else {
      _log('📦 POST Request Body: No body data');
    }

    try {
      final response = await _dio.post(
        endpoint,
        data: data != null ? jsonEncode(data) : null,
      );

      return _handleResponse(response, "POST");
    } on DioException catch (e) {
      return _handleDioException(e, "POST");
    } catch (e) {
      _log('POST Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Interceptor PUT Method
  Future<ApiResponse<Map<String, dynamic>>> put({
    required String endpoint,
    Map<String, dynamic>? data,
  }) async {
    String url = '${_dio.options.baseUrl}$endpoint';
    _log('📤 PUT Request URL: $url');

    if (data != null) {
      _log('📦 PUT Request Body: ${jsonEncode(data)}');
    } else {
      _log('📦 PUT Request Body: No body data');
    }

    try {
      final response = await _dio.put(
        endpoint,
        data: data != null ? jsonEncode(data) : null,
      );

      return _handleResponse(response, "PUT");
    } on DioException catch (e) {
      return _handleDioException(e, "PUT");
    } catch (e) {
      _log('PUT Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Interceptor DELETE Method
  Future<ApiResponse<Map<String, dynamic>>> delete({
    required String endpoint,
    Map<String, dynamic>? data,
  }) async {
    String url = '${_dio.options.baseUrl}$endpoint';
    _log('🗑️ DELETE Request URL: $url');

    if (data != null) {
      _log('📦 DELETE Request Body: ${jsonEncode(data)}');
    } else {
      _log('📦 DELETE Request Body: No body data');
    }

    try {
      final response = await _dio.delete(
        endpoint,
        data: data != null ? jsonEncode(data) : null,
      );

      return _handleResponse(response, "DELETE");
    } on DioException catch (e) {
      return _handleDioException(e, "DELETE");
    } catch (e) {
      _log('DELETE Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Global POST Method
  Future<ApiResponse<Map<String, dynamic>>> globalPost({
    required String endpoint,
    Map<String, dynamic>? data,
  }) async {
    try {
      String url = '$baseUrl$endpoint';
      _log('Global POST Request URL: $url', icon: '✅');

      if (data != null) {
        _log('📦 Global POST Request Body: ${jsonEncode(data)}');
      } else {
        _log('📦 Global POST Request Body: No body data');
      }

      final response = await _dio.post(
        url,
        data: data != null ? jsonEncode(data) : null,
        options: Options(headers: _baseHeaders),
      );

      return _handleResponse(response, "Global POST");
    } on DioException catch (e) {
      return _handleDioException(e, "Global POST");
    } catch (e) {
      _log('Global POST Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Global GET Method
  Future<ApiResponse<Map<String, dynamic>>> globalGet({
    required String endpoint,
  }) async {
    try {
      String url = '$baseUrl$endpoint';
      _log('Global GET Request URL: $url', icon: '✅');

      final response = await _dio.get(
        url,
        options: Options(headers: _baseHeaders),
      );

      return _handleResponse(response, "Global GET");
    } on DioException catch (e) {
      return _handleDioException(e, "Global GET");
    } catch (e) {
      _log('Global GET Exception: ${e.toString()}', icon: '❌');
      _showToast('An unexpected error occurred. Please try again.');
      return ApiResponse.error(e.toString());
    }
  }

  // Handling Dio Exception
  ApiResponse<Map<String, dynamic>> _handleDioException(
    DioException e,
    String requestType,
  ) {
    if (e.type == DioExceptionType.connectionTimeout ||
        e.type == DioExceptionType.receiveTimeout) {
      _log('$requestType TimeoutException: Request timed out', icon: '⏳');
      _showToast('Request timed out. Please try again.');
      return ApiResponse.error('Request timed out');
    } else if (e.type == DioExceptionType.connectionError) {
      _log('$requestType SocketException: No internet connection', icon: '🚫');
      _showToast('No internet connection. Please check your network.');
      return ApiResponse.error('No internet connection');
    } else if (e.response != null) {
      return _handleDioErrorResponse(e.response!, requestType);
    } else {
      _log('$requestType DioException: ${e.message}', icon: '🚫');
      _showToast('An error occurred. Please try again.');
      return ApiResponse.error(e.message ?? 'An error occurred');
    }
  }

  // Handle API Response
  ApiResponse<Map<String, dynamic>> _handleResponse(
    Response response,
    String requestType,
  ) {
    _log('Handling Response - Status Code: ${response.statusCode}', icon: '📥');

    switch (response.statusCode) {
      case 200:
      case 201:
        final jsonData = response.data as Map<String, dynamic>;
        _log('$requestType Response: $jsonData', icon: '✅');
        return ApiResponse.completed(jsonData);
      default:
        _log('Unknown Status Code: ${response.statusCode}', icon: '❓');
        return ApiResponse.error('Error occurred: ${response.statusCode}');
    }
  }

  // Handle Dio Error Exception
  ApiResponse<Map<String, dynamic>> _handleDioErrorResponse(
    Response response,
    String requestType,
  ) {
    _log(
      'Handling Error Response - Status Code: ${response.statusCode}',
      icon: '⚠️',
    );

    switch (response.statusCode) {
      case 400:
      case 401:
        final jsonResponse = response.data as Map<String, dynamic>? ?? {};
        _log('$requestType Response: ${jsonResponse.toString()}', icon: '❌');
        final errorMessages = jsonResponse['message'] as String? ?? "";
        final ThemeController themeController = Get.find<ThemeController>();
        Get.dialog(
          PopScope(
            canPop: false,
            child: Dialog(
              insetPadding: EdgeInsets.zero,
              backgroundColor:
                  themeController.isDarkMode.value
                      ? AppColors.darkSecondary
                      : AppColors.white,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12),
              ),
              child: SizedBox(
                width: 324,
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(20, 20, 20, 30),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const SizedBox(height: 30),
                      Container(
                        padding: const EdgeInsets.all(15),
                        width: 60,
                        height: 60,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(52),
                          color: AppColors.error.withValues(alpha: 0.10),
                        ),
                        child: Image.asset(
                          PngAssets.commonAlertIcon,
                          width: 30,
                          fit: BoxFit.contain,
                        ),
                      ),
                      const SizedBox(height: 16),
                      Column(
                        children: [
                          Text(
                            "common.alertDialog.unauthorizedTitle".trns(),
                            style: TextStyle(
                              fontWeight: FontWeight.w700,
                              fontSize: 18,
                              color:
                                  themeController.isDarkMode.value
                                      ? AppColors.darkTextPrimary
                                      : AppColors.textPrimary,
                            ),
                          ),
                          const SizedBox(height: 10),
                          Text(
                            textAlign: TextAlign.center,
                            "common.alertDialog.unauthorizedMessage".trns(),
                            style: TextStyle(
                              fontWeight: FontWeight.w400,
                              fontSize: 12,
                              color:
                                  themeController.isDarkMode.value
                                      ? AppColors.darkTextPrimary
                                      : AppColors.textPrimary,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 30),
                      GestureDetector(
                        onTap: () => Get.offAllNamed(BaseRoute.signIn),
                        child: Container(
                          width: 88,
                          height: 32,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(6),
                            color:
                                themeController.isDarkMode.value
                                    ? AppColors.darkPrimary
                                    : AppColors.primary,
                          ),
                          child: Center(
                            child: Text(
                              textAlign: TextAlign.center,
                              "Ok",
                              style: TextStyle(
                                fontWeight: FontWeight.w600,
                                fontSize: 13,
                                color:
                                    themeController.isDarkMode.value
                                        ? AppColors.black
                                        : AppColors.white,
                              ),
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        );
        _showToast(errorMessages);
        return ApiResponse.error(errorMessages);

      case 403:
      case 404:
      case 422:
        final jsonResponse = response.data as Map<String, dynamic>? ?? {};
        _log('$requestType Response: ${jsonResponse.toString()}', icon: '❌');
        final errorMessages = jsonResponse['message'] as String? ?? "";
        _showToast(errorMessages);
        return ApiResponse.error(errorMessages);

      case 500:
        final jsonResponse = response.data as Map<String, dynamic>? ?? {};
        _log('$requestType Response: ${jsonResponse.toString()}', icon: '❌');
        final errorMessages = jsonResponse['message'] as String? ?? "";
        _showToast(errorMessages);
        return ApiResponse.error(errorMessages);

      default:
        _log('Unknown Error: ${response.statusCode}', icon: '❓');
        _showToast('An error occurred. Please try again.');
        return ApiResponse.error('Error occurred: ${response.statusCode}');
    }
  }

  // Utilities
  Map<String, String> get _baseHeaders {
    return {'Content-Type': 'application/json', 'Accept': 'application/json'};
  }

  void _log(String message, {String icon = '📄'}) {
    if (kDebugMode) {
      debugPrint('$icon $message');
    }
  }

  void _showToast(String message) {
    Fluttertoast.showToast(
      msg: message,
      backgroundColor: AppColors.error,
      toastLength: Toast.LENGTH_LONG,
      gravity: ToastGravity.BOTTOM,
    );
  }
}
