import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../core/constants/app_constants.dart';
import '../../core/errors/failures.dart';
import '../../domain/repositories/warehouse_location_repository.dart';
import '../../models/warehouse_location_model.dart';
import '../datasources/remote/warehouse_location_remote_datasource.dart';
import '../models/common/paginated_response.dart';
import '../models/warehouse/warehouse_dto.dart';

/// 창고 위치 Repository 구현체
/// 창고 위치 및 장비 입고지 관리 작업을 처리하며 도메인 모델과 API DTO 간 변환을 담당
@Injectable(as: WarehouseLocationRepository)
class WarehouseLocationRepositoryImpl implements WarehouseLocationRepository {
  final WarehouseLocationRemoteDataSource remoteDataSource;

  WarehouseLocationRepositoryImpl({required this.remoteDataSource});

  @override
  Future<Either<Failure, PaginatedResponse<WarehouseLocation>>> getWarehouseLocations({
    int? page,
    int? limit,
    String? search,
    String? locationType,
    bool? isActive,
    bool? hasEquipment,
    String? sortBy,
    String? sortOrder,
  }) async {
    try {
      final result = await remoteDataSource.getWarehouseLocations(
        page: page ?? 1,
        perPage: limit ?? AppConstants.warehousePageSize,
        search: search,
        filters: {
          if (locationType != null) 'location_type': locationType,
          if (isActive != null) 'is_active': isActive,
          if (hasEquipment != null) 'has_equipment': hasEquipment,
        },
      );
      
      // DTO를 도메인 모델로 변환
      final warehouseLocations = result.items.map((dto) => _mapDtoToDomain(dto)).toList();
      
      final paginatedResult = PaginatedResponse<WarehouseLocation>(
        items: warehouseLocations,
        page: result.page,
        size: result.perPage,
        totalElements: result.total,
        totalPages: result.totalPages,
        first: result.page == 1,
        last: result.page == result.totalPages,
      );
      
      return Right(paginatedResult);
    } catch (e) {
      return Left(ServerFailure(
        message: '창고 위치 목록 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, WarehouseLocation>> getWarehouseLocationById(int id) async {
    try {
      final result = await remoteDataSource.getWarehouseLocationDetail(id);
      final warehouseLocation = _mapDetailDtoToDomain(result);
      return Right(warehouseLocation);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '해당 창고 위치를 찾을 수 없습니다.',
          resourceType: 'WarehouseLocation',
          resourceId: id.toString(),
        ));
      }
      return Left(ServerFailure(
        message: '창고 위치 상세 정보 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, WarehouseLocation>> createWarehouseLocation(WarehouseLocation warehouseLocation) async {
    try {
      final request = _mapDomainToCreateRequest(warehouseLocation);
      final result = await remoteDataSource.createWarehouseLocation(request);
      final createdWarehouseLocation = _mapDetailDtoToDomain(result);
      return Right(createdWarehouseLocation);
    } catch (e) {
      if (e.toString().contains('중복')) {
        return Left(DuplicateFailure(
          message: '이미 존재하는 창고명입니다.',
          field: 'name',
          value: warehouseLocation.name,
        ));
      }
      if (e.toString().contains('유효성')) {
        return Left(ValidationFailure(
          message: '입력 데이터가 올바르지 않습니다.',
        ));
      }
      return Left(ServerFailure(
        message: '창고 위치 생성 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, WarehouseLocation>> updateWarehouseLocation(int id, WarehouseLocation warehouseLocation) async {
    try {
      final request = _mapDomainToUpdateRequest(warehouseLocation);
      final result = await remoteDataSource.updateWarehouseLocation(id, request);
      final updatedWarehouseLocation = _mapDetailDtoToDomain(result);
      return Right(updatedWarehouseLocation);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '수정할 창고 위치를 찾을 수 없습니다.',
          resourceType: 'WarehouseLocation',
          resourceId: id.toString(),
        ));
      }
      if (e.toString().contains('중복')) {
        return Left(DuplicateFailure(
          message: '이미 존재하는 창고명입니다.',
          field: 'name',
          value: warehouseLocation.name,
        ));
      }
      return Left(ServerFailure(
        message: '창고 위치 정보 수정 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> deleteWarehouseLocation(int id) async {
    try {
      await remoteDataSource.deleteWarehouseLocation(id);
      return const Right(null);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '삭제할 창고 위치를 찾을 수 없습니다.',
          resourceType: 'WarehouseLocation',
          resourceId: id.toString(),
        ));
      }
      if (e.toString().contains('참조')) {
        return Left(BusinessFailure(
          message: '해당 창고에 보관 중인 장비가 있어 삭제할 수 없습니다.',
        ));
      }
      return Left(ServerFailure(
        message: '창고 위치 삭제 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, WarehouseLocation>> toggleWarehouseLocationStatus(int id) async {
    try {
      // 현재 창고 위치 정보 조회
      final currentWarehouse = await remoteDataSource.getWarehouseLocationDetail(id);
      final newStatus = !currentWarehouse.isActive;
      
      // 상태 업데이트
      await remoteDataSource.updateWarehouseLocationStatus(id, newStatus);
      
      // 업데이트된 창고 위치 정보 재조회
      final updatedWarehouse = await remoteDataSource.getWarehouseLocationDetail(id);
      final warehouseLocation = _mapDetailDtoToDomain(updatedWarehouse);
      
      return Right(warehouseLocation);
    } catch (e) {
      if (e.toString().contains('404')) {
        return Left(NotFoundFailure(
          message: '상태를 변경할 창고 위치를 찾을 수 없습니다.',
          resourceType: 'WarehouseLocation',
          resourceId: id.toString(),
        ));
      }
      return Left(ServerFailure(
        message: '창고 위치 상태 변경 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, bool>> hasEquipment(int id) async {
    try {
      final hasEquipment = await remoteDataSource.checkWarehouseHasEquipment(id);
      return Right(hasEquipment);
    } catch (e) {
      return Left(ServerFailure(
        message: '창고 장비 보유 여부 확인 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, int>> getEquipmentCount(int id) async {
    // TODO: API에서 창고별 장비 수량 조회 기능이 구현되면 추가
    try {
      // 임시로 0 반환 - API 구현 후 수정 필요
      return const Right(0);
    } catch (e) {
      return Left(ServerFailure(
        message: '창고 장비 수량 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, PaginatedResponse<dynamic>>> getEquipmentByWarehouse(
    int warehouseId, {
    int? page,
    int? limit,
  }) async {
    // TODO: API에서 창고별 장비 목록 조회 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '창고별 장비 목록 조회 기능이 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, Map<int, double>>> getWarehouseUtilization() async {
    // TODO: API에서 창고 사용률 통계 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '창고 사용률 통계 기능이 아직 구현되지 않았습니다.',
    ));
  }

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

  @override
  Future<Either<Failure, bool>> isDuplicateWarehouseName(String name, {int? excludeId}) async {
    try {
      final isDuplicate = await remoteDataSource.checkDuplicateWarehouseName(name);
      // excludeId가 있는 경우 해당 ID 제외 로직 추가 필요
      return Right(isDuplicate);
    } catch (e) {
      return Left(ServerFailure(
        message: '중복 창고명 확인 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, List<WarehouseLocation>>> searchWarehouseLocations(String query, {int? limit}) async {
    try {
      final result = await remoteDataSource.getWarehouseLocations(
        page: 1,
        perPage: limit ?? 10,
        search: query,
      );
      
      final warehouseLocations = result.items.map((dto) => _mapDtoToDomain(dto)).toList();
      return Right(warehouseLocations);
    } catch (e) {
      return Left(ServerFailure(
        message: '창고 위치 검색 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, List<WarehouseLocation>>> getActiveWarehouseLocations() async {
    try {
      final result = await remoteDataSource.getWarehouseLocations(
        page: 1,
        perPage: 100, // 활성 창고 모두 조회
        filters: {'is_active': true},
      );
      
      final activeWarehouses = result.items.map((dto) => _mapDtoToDomain(dto)).toList();
      return Right(activeWarehouses);
    } catch (e) {
      return Left(ServerFailure(
        message: '활성 창고 위치 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, WarehouseLocation>> updateWarehouseCapacity(
    int id, 
    int totalCapacity, 
    int usedCapacity,
  ) async {
    // TODO: API에서 창고 용량 업데이트 기능이 구현되면 추가
    return const Left(ServerFailure(
      message: '창고 용량 업데이트 기능이 아직 구현되지 않았습니다.',
    ));
  }

  // Private 매퍼 메서드들
  
  WarehouseLocation _mapDtoToDomain(WarehouseDto dto) {
    return WarehouseLocation(
      id: dto.id ?? 0,
      name: dto.name,
      address: '', // 백엔드에서 미지원
      managerName: '', // 백엔드에서 미지원
      managerPhone: '', // 백엔드에서 미지원
      capacity: 0, // 백엔드에서 미지원
      remark: dto.remark,
      isActive: !dto.isDeleted, // isActive는 isDeleted의 반대
      createdAt: dto.registeredAt,
    );
  }
  
  WarehouseLocation _mapDetailDtoToDomain(WarehouseDto dto) {
    return WarehouseLocation(
      id: dto.id ?? 0,
      name: dto.name,
      address: '', // 백엔드에서 미지원
      managerName: '', // 백엔드에서 미지원
      managerPhone: '', // 백엔드에서 미지원
      capacity: 0, // 백엔드에서 미지원
      remark: dto.remark,
      isActive: !dto.isDeleted, // isActive는 isDeleted의 반대
      createdAt: dto.registeredAt,
    );
  }
  
  // WarehouseLocationType enum이 WarehouseLocation 모델에 없으므로 제거
  // 필요시 나중에 모델 업데이트 후 재추가
  
  WarehouseRequestDto _mapDomainToCreateRequest(WarehouseLocation warehouseLocation) {
    return WarehouseRequestDto(
      name: warehouseLocation.name,
      zipcodesZipcode: null, // zipcodes FK (별도 처리 필요)
      remark: warehouseLocation.remark,
    );
  }
  
  WarehouseUpdateRequestDto _mapDomainToUpdateRequest(WarehouseLocation warehouseLocation) {
    return WarehouseUpdateRequestDto(
      name: warehouseLocation.name,
      zipcodesZipcode: null, // zipcodes FK (별도 처리 필요)
      remark: warehouseLocation.remark,
    );
  }
  
  // WarehouseLocationType enum이 WarehouseLocation 모델에 없으므로 제거
  // 필요시 나중에 모델 업데이트 후 재추가
}