import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../core/errors/failures.dart';
import '../../domain/repositories/license_repository.dart';
import '../../models/license_model.dart';
import '../datasources/remote/license_remote_datasource.dart';
import '../models/common/paginated_response.dart';
import '../models/dashboard/license_expiry_summary.dart';
import '../models/license/license_dto.dart';
import '../models/license/license_request_dto.dart';

/// 라이선스 Repository 구현체
/// 라이선스 및 유지보수 계약 관리 작업을 처리하며 도메인 모델과 API DTO 간 변환을 담당
@Injectable(as: LicenseRepository)
class LicenseRepositoryImpl implements LicenseRepository {
  final LicenseRemoteDataSource remoteDataSource;

  LicenseRepositoryImpl({required this.remoteDataSource});

  @override
  Future<Either<Failure, PaginatedResponse<License>>> getLicenses({
    int? page,
    int? limit,
    String? search,
    int? companyId,
    String? equipmentType,
    String? expiryStatus,
    String? sortBy,
    String? sortOrder,
  }) async {
    try {
      final result = await remoteDataSource.getLicenses(
        page: page ?? 1,
        perPage: limit ?? 20,
        isActive: null, // expiryStatus에 따른 필터링 로직 필요 시 추가
        companyId: companyId,
        assignedUserId: null,
        licenseType: equipmentType,
      );
      
      // DTO를 도메인 모델로 변환
      final licenses = result.items.map((dto) => _mapDtoToDomain(dto)).toList();
      
      // 검색 필터링 (서버에서 지원하지 않는 경우 클라이언트 측에서 처리)
      if (search != null && search.isNotEmpty) {
        final filteredLicenses = licenses.where((license) {
          final searchLower = search.toLowerCase();
          return (license.productName?.toLowerCase().contains(searchLower) ?? false) ||
                 (license.companyName?.toLowerCase().contains(searchLower) ?? false) ||
                 (license.vendor?.toLowerCase().contains(searchLower) ?? false);
        }).toList();
        
        final paginatedResult = PaginatedResponse<License>(
          items: filteredLicenses,
          page: result.page,
          size: 20,
          totalElements: filteredLicenses.length,
          totalPages: (filteredLicenses.length / 20).ceil(),
          first: result.page == 0,
          last: result.page >= (filteredLicenses.length / 20).ceil() - 1,
        );
        
        return Right(paginatedResult);
      }
      
      final paginatedResult = PaginatedResponse<License>(
        items: licenses,
        page: result.page,
        size: 20,
        totalElements: result.total,
        totalPages: (result.total / 20).ceil(),
        first: result.page == 0,
        last: result.page >= (result.total / 20).ceil() - 1,
      );
      
      return Right(paginatedResult);
    } catch (e) {
      return Left(ServerFailure(
        message: '라이선스 목록 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, License>> getLicenseById(int id) async {
    try {
      final result = await remoteDataSource.getLicenseById(id);
      final license = _mapDtoToDomain(result);
      return Right(license);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '해당 라이선스를 찾을 수 없습니다.',
          resourceType: 'License',
          resourceId: id.toString(),
        ));
      }
      return Left(ServerFailure(
        message: '라이선스 상세 정보 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, License>> createLicense(License license) async {
    try {
      final request = _mapDomainToCreateRequest(license);
      final result = await remoteDataSource.createLicense(request);
      final createdLicense = _mapDtoToDomain(result);
      return Right(createdLicense);
    } catch (e) {
      if (e.toString().contains('중복')) {
        return Left(DuplicateFailure(
          message: '이미 존재하는 라이선스입니다.',
          field: 'licenseKey',
          value: license.licenseKey,
        ));
      }
      if (e.toString().contains('유효성')) {
        return Left(ValidationFailure(
          message: '입력 데이터가 올바르지 않습니다.',
        ));
      }
      return Left(ServerFailure(
        message: '라이선스 생성 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, License>> updateLicense(int id, License license) async {
    try {
      final request = _mapDomainToUpdateRequest(license);
      final result = await remoteDataSource.updateLicense(id, request);
      final updatedLicense = _mapDtoToDomain(result);
      return Right(updatedLicense);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '수정할 라이선스를 찾을 수 없습니다.',
          resourceType: 'License',
          resourceId: id.toString(),
        ));
      }
      if (e.toString().contains('중복')) {
        return Left(DuplicateFailure(
          message: '이미 존재하는 라이선스키입니다.',
          field: 'licenseKey',
          value: license.licenseKey,
        ));
      }
      return Left(ServerFailure(
        message: '라이선스 정보 수정 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> deleteLicense(int id) async {
    try {
      await remoteDataSource.deleteLicense(id);
      return const Right(null);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '삭제할 라이선스를 찾을 수 없습니다.',
          resourceType: 'License',
          resourceId: id.toString(),
        ));
      }
      if (e.toString().contains('참조')) {
        return Left(BusinessFailure(
          message: '해당 라이선스에 연결된 데이터가 있어 삭제할 수 없습니다.',
        ));
      }
      return Left(ServerFailure(
        message: '라이선스 삭제 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, List<License>>> getExpiringLicenses({int days = 30, int? companyId}) async {
    // TODO: API에서 만료 예정 라이선스 조회 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '만료 예정 라이선스 조회 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, List<License>>> getExpiredLicenses({int? companyId}) async {
    // TODO: API에서 만료된 라이선스 조회 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '만료된 라이선스 조회 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, LicenseExpirySummary>> getLicenseExpirySummary() async {
    // TODO: API에서 라이선스 만료 요약 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '라이선스 만료 요약 조회 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, License>> renewLicense(int id, DateTime newExpiryDate, {double? renewalCost, String? renewalNote}) async {
    // TODO: API에서 라이선스 갱신 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '라이선스 갱신 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, Map<String, int>>> getLicenseStatsByCompany(int companyId) async {
    // TODO: API에서 회사별 라이선스 통계 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '회사별 라이선스 통계 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, Map<String, int>>> getLicenseCountByType() async {
    // TODO: API에서 라이선스 유형별 통계 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '라이선스 유형별 통계 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, void>> setExpiryNotification(int licenseId, {int notifyDays = 30}) async {
    // TODO: API에서 만료 알림 설정 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '만료 알림 설정 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, List<License>>> searchLicenses(String query, {int? companyId, int? limit}) async {
    try {
      final result = await remoteDataSource.getLicenses(
        page: 1,
        perPage: limit ?? 10,
        companyId: companyId,
      );
      
      // 클라이언트 측에서 검색 필터링
      final searchLower = query.toLowerCase();
      final filteredLicenses = result.items
          .where((dto) {
            final license = _mapDtoToDomain(dto);
            return (license.productName?.toLowerCase().contains(searchLower) ?? false) ||
                   (license.companyName?.toLowerCase().contains(searchLower) ?? false) ||
                   (license.vendor?.toLowerCase().contains(searchLower) ?? false);
          })
          .map((dto) => _mapDtoToDomain(dto))
          .toList();
      
      return Right(filteredLicenses);
    } catch (e) {
      return Left(ServerFailure(
        message: '라이선스 검색 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  // Private 매퍼 메서드들
  
  License _mapDtoToDomain(LicenseDto dto) {
    return License(
      id: dto.id,
      licenseKey: dto.licenseKey,
      productName: dto.productName,
      vendor: dto.vendor,
      licenseType: dto.licenseType,
      userCount: dto.userCount,
      purchaseDate: dto.purchaseDate,
      expiryDate: dto.expiryDate,
      purchasePrice: dto.purchasePrice,
      companyId: dto.companyId,
      branchId: dto.branchId,
      assignedUserId: dto.assignedUserId,
      remark: dto.remark,
      isActive: dto.isActive,
      createdAt: dto.createdAt,
      updatedAt: dto.updatedAt,
      companyName: dto.companyName,
      branchName: dto.branchName,
      assignedUserName: dto.assignedUserName,
    );
  }
  
  CreateLicenseRequest _mapDomainToCreateRequest(License license) {
    return CreateLicenseRequest(
      licenseKey: license.licenseKey,
      productName: license.productName,
      vendor: license.vendor,
      licenseType: license.licenseType,
      userCount: license.userCount,
      purchaseDate: license.purchaseDate,
      expiryDate: license.expiryDate,
      purchasePrice: license.purchasePrice,
      companyId: license.companyId,
      branchId: license.branchId,
      remark: license.remark,
    );
  }
  
  UpdateLicenseRequest _mapDomainToUpdateRequest(License license) {
    return UpdateLicenseRequest(
      licenseKey: license.licenseKey,
      productName: license.productName,
      vendor: license.vendor,
      licenseType: license.licenseType,
      userCount: license.userCount,
      purchaseDate: license.purchaseDate,
      expiryDate: license.expiryDate,
      purchasePrice: license.purchasePrice,
      remark: license.remark,
      isActive: license.isActive,
    );
  }
}