import 'dart:io';
import 'package:dio/dio.dart';
import '../../core/error/exceptions.dart';
import '../../core/network/api_client.dart';
import '../dto/attendance_response_dto.dart';
import '../dto/attendance_record_dto.dart';
import '../dto/overtime_dto.dart';
import '../dto/reward_dto.dart';
import '../dto/punishment_dto.dart';
import '../dto/salary_response_dto.dart';

abstract class AttendanceRemoteDataSource {
  Future<AttendanceResponseDto> login({
    required String employeeId,
    required File faceImage,
  });

  Future<AttendanceResponseDto> logout({
    required String employeeId,
    required File faceImage,
  });

  Future<List<AttendanceRecordDto>> getAttendanceRecords({
    required String employeeId,
  });
  Future<List<OvertimeDto>> getExtraHours({required String employeeId});
  Future<List<RewardDto>> getRewards({required String employeeId});
  Future<List<PunishmentDto>> getPunishments({required String employeeId});
  Future<SalaryResponseDto> calculateSalary({
    required String employeeId,
    required int month,
    required int year,
  });
}

class AttendanceRemoteDataSourceImpl implements AttendanceRemoteDataSource {
  final ApiClient apiClient;

  AttendanceRemoteDataSourceImpl({required this.apiClient});
  @override
  Future<AttendanceResponseDto> login({
    required String employeeId,
    required File faceImage,
  }) async {
    try {
      final formData = FormData.fromMap({
        'EmployeeId': employeeId,
        'FaceImage': await MultipartFile.fromFile(faceImage.path),
      });

      final response = await apiClient.post(
        '/Attendance/login',
        data: formData,
        options: Options(contentType: 'multipart/form-data'),
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        final responseData = response.data;

        if (responseData is Map<String, dynamic>) {
          return AttendanceResponseDto.fromJson(responseData);
        } else {
          throw ServerException(
            message: 'استجابة غير صحيحة من الخادم',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ServerException(
          message: 'فشل تسجيل الدخول',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw NetworkException(message: 'انتهت مهلة الاتصال');
      } else if (e.type == DioExceptionType.connectionError) {
        throw NetworkException(message: 'لا يوجد اتصال بالانترنيت');
      } else if (e.response?.statusCode == 500) {
        throw ServerException(message: 'خطأ في الخادم يرجى المحاولة لاحقا');
      } else if (e.response != null) {
        final message =
            e.response?.data?['message'] ??
            e.response?.data?['error'] ??
            'فشل تسجيل الدخول';

        throw ServerException(
          message: message.toString(),
          statusCode: e.response?.statusCode,
        );
      } else {
        throw NetworkException(message: 'خطأ في الانترنيت يرجى المحاولة لاحقا');
      }
    } catch (e) {
      if (e is ServerException || e is NetworkException) {
        rethrow;
      }
      print('خطأ غير متوقع: $e');
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }

  @override
  Future<AttendanceResponseDto> logout({
    required String employeeId,
    required File faceImage,
  }) async {
    try {
      final formData = FormData.fromMap({
        'EmployeeId': employeeId,
        'FaceImage': await MultipartFile.fromFile(faceImage.path),
      });

      final response = await apiClient.post(
        '/Attendance/logout',
        data: formData,
        options: Options(contentType: 'multipart/form-data'),
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        final responseData = response.data;

        if (responseData is Map<String, dynamic>) {
          return AttendanceResponseDto.fromJson(responseData);
        } else {
          throw ServerException(
            message: 'استجابة غير صحيحة من الخادم',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ServerException(
          message: 'فشل تسجيل الخروج',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw NetworkException(message: 'انتهت مهلة الاتصال');
      } else if (e.type == DioExceptionType.connectionError) {
        throw NetworkException(message: 'لا يوجد اتصال بالانترنيت');
      } else if (e.response?.statusCode == 500) {
        throw ServerException(message: 'خطأ في الخادم يرجى المحاولة لاحقا');
      } else if (e.response != null) {
        final message =
            e.response?.data?['message'] ??
            e.response?.data?['error'] ??
            'فشل تسجيل الخروج';

        throw ServerException(
          message: message.toString(),
          statusCode: e.response?.statusCode,
        );
      } else {
        throw NetworkException(message: 'خطأ في الانترنيت يرجى المحاولة لاحقا');
      }
    } catch (e) {
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }

  @override
  Future<List<AttendanceRecordDto>> getAttendanceRecords({
    required String employeeId,
  }) async {
    try {
      final response = await apiClient.get(
        '/Attendance',
        queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
      );

      if (response.statusCode == 200) {
        final data = response.data;
        if (data is Map<String, dynamic> &&
            data['data'] != null &&
            data['data']['items'] is List) {
          final items = data['data']['items'] as List;
          return items.map((e) => AttendanceRecordDto.fromJson(e)).toList();
        }
        return [];
      } else {
        throw ServerException(
          message: 'فشل في جلب البيانات',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      throw ServerException(
        message: e.message ?? 'Unknown error',
        statusCode: e.response?.statusCode,
      );
    } catch (e) {
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }

  @override
  Future<List<OvertimeDto>> getExtraHours({required String employeeId}) async {
    try {
      final response = await apiClient.get(
        '/ExtraHours',
        queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
      );

      if (response.statusCode == 200) {
        final responseData = response.data;

        if (responseData is Map<String, dynamic>) {
          return OvertimeListResponseDto.fromJson(responseData).items;
        } else {
          throw ServerException(
            message: 'استجابة غير صحيحة من الخادم',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ServerException(
          message: 'فشل في جلب البيانات',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      throw ServerException(
        message: e.message ?? 'Unknown error',
        statusCode: e.response?.statusCode,
      );
    } catch (e) {
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }

  @override
  Future<List<RewardDto>> getRewards({required String employeeId}) async {
    try {
      final response = await apiClient.get(
        '/Reward',
        queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
      );

      if (response.statusCode == 200) {
        final responseData = response.data;
        if (responseData is Map<String, dynamic>) {
          return RewardListResponseDto.fromJson(responseData).items;
        }
        return [];
      } else {
        throw ServerException(
          message: 'فشل في جلب المكافآت',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      throw ServerException(
        message: e.message ?? 'Unknown error',
        statusCode: e.response?.statusCode,
      );
    } catch (e) {
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }

  @override
  Future<List<PunishmentDto>> getPunishments({
    required String employeeId,
  }) async {
    try {
      final response = await apiClient.get(
        '/Punishment',
        queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
      );

      if (response.statusCode == 200) {
        final responseData = response.data;
        if (responseData is Map<String, dynamic>) {
          return PunishmentListResponseDto.fromJson(responseData).items;
        }
        return [];
      } else {
        throw ServerException(
          message: 'فشل في جلب البيانات',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      throw ServerException(
        message: e.message ?? 'Unknown error',
        statusCode: e.response?.statusCode,
      );
    } catch (e) {
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }

  @override
  Future<SalaryResponseDto> calculateSalary({
    required String employeeId,
    required int month,
    required int year,
  }) async {
    try {
      final response = await apiClient.get(
        '/SalaryRecord/calculate',
        queryParameters: {
          'EmployeeId': employeeId,
          'Month': month,
          'Year': year,
        },
      );

      print('Salary Response Status: ${response.statusCode}');
      if (response.statusCode == 200 || response.statusCode == 201) {
        final responseData = response.data;
        print(
          'Salary Response Data: $responseData (${responseData.runtimeType})',
        );

        if (responseData is Map<String, dynamic>) {
          return SalaryResponseDto.fromJson(responseData);
        } else if (responseData is num) {
          // Handle case where API returns raw number
          return SalaryResponseDto(
            isSuccess: true,
            message: 'Success',
            data: SalaryDataDto(netAmount: responseData.toDouble()),
          );
        } else if (responseData is String &&
            double.tryParse(responseData) != null) {
          // Handle case where API returns raw numeric string
          return SalaryResponseDto(
            isSuccess: true,
            message: 'Success',
            data: SalaryDataDto(netAmount: double.parse(responseData)),
          );
        } else {
          throw ServerException(
            message: 'استجابة غير صحيحة من الخادم: $responseData',
            statusCode: response.statusCode,
          );
        }
      } else {
        throw ServerException(
          message: 'فشل في حساب الراتب (Status: ${response.statusCode})',
          statusCode: response.statusCode,
        );
      }
    } on DioException catch (e) {
      throw ServerException(
        message: e.message ?? 'Unknown error',
        statusCode: e.response?.statusCode,
      );
    } catch (e) {
      throw ServerException(message: 'خطأ غير متوقع');
    }
  }
}
