import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import 'package:superport/core/errors/failures.dart';
import 'package:superport/data/models/administrator_dto.dart';
import 'package:superport/domain/repositories/administrator_repository.dart';
import 'package:superport/core/constants/app_constants.dart';

/// 관리자 UseCase 인터페이스 (비즈니스 로직)
abstract class AdministratorUseCase {
  Future<Either<Failure, AdministratorListResponse>> getAdministrators({
    int page = 1,
    int pageSize = AppConstants.adminPageSize,
    String? search,
  });
  
  Future<Either<Failure, AdministratorDto>> getAdministratorById(int id);
  
  Future<Either<Failure, AdministratorDto>> createAdministrator(
    AdministratorRequestDto administrator,
  );
  
  Future<Either<Failure, AdministratorDto>> updateAdministrator(
    int id,
    AdministratorUpdateRequestDto administrator,
  );
  
  Future<Either<Failure, void>> deleteAdministrator(int id);
  
  Future<Either<Failure, bool>> checkEmailDuplicate(String email, {int? excludeId});
  
  Future<Either<Failure, AdministratorDto>> authenticateAdministrator(
    String email,
    String password,
  );
  
  Future<Either<Failure, bool>> validateAdministratorData(
    String name,
    String email,
    String phone,
    String mobile,
  );
}

/// 관리자 UseCase 구현체
@Injectable(as: AdministratorUseCase)
class AdministratorUseCaseImpl implements AdministratorUseCase {
  final AdministratorRepository _repository;

  AdministratorUseCaseImpl(this._repository);

  @override
  Future<Either<Failure, AdministratorListResponse>> getAdministrators({
    int page = 1,
    int pageSize = AppConstants.adminPageSize,
    String? search,
  }) async {
    // 비즈니스 로직: 페이지네이션 유효성 검사
    if (page < 1) page = 1;
    if (pageSize < 1 || pageSize > 100) pageSize = AppConstants.adminPageSize;

    return await _repository.getAdministrators(
      page: page,
      pageSize: pageSize,
      search: search,
    );
  }

  @override
  Future<Either<Failure, AdministratorDto>> getAdministratorById(int id) async {
    // 비즈니스 규칙: ID 유효성 검사
    if (id <= 0) {
      return Left(ValidationFailure(
        message: '유효하지 않은 관리자 ID입니다.',
      ));
    }

    return await _repository.getAdministratorById(id);
  }

  @override
  Future<Either<Failure, AdministratorDto>> createAdministrator(
    AdministratorRequestDto administrator,
  ) async {
    // 비즈니스 규칙 검증
    final validationResult = await validateAdministratorData(
      administrator.name,
      administrator.email,
      administrator.phone,
      administrator.mobile,
    );
    
    return validationResult.fold(
      (failure) => Left(failure),
      (isValid) async {
        if (!isValid) {
          return Left(ValidationFailure(
            message: '관리자 정보가 유효하지 않습니다.',
          ));
        }

        // 이메일 중복 검사
        final duplicateResult = await checkEmailDuplicate(administrator.email);
        return duplicateResult.fold(
          (failure) => Left(failure),
          (isDuplicate) async {
            if (isDuplicate) {
              return Left(DuplicateFailure(
                message: '이미 사용 중인 이메일 주소입니다.',
              ));
            }

            return await _repository.createAdministrator(administrator);
          },
        );
      },
    );
  }

  @override
  Future<Either<Failure, AdministratorDto>> updateAdministrator(
    int id,
    AdministratorUpdateRequestDto administrator,
  ) async {
    // 비즈니스 규칙: ID 유효성 검사
    if (id <= 0) {
      return Left(ValidationFailure(
        message: '유효하지 않은 관리자 ID입니다.',
      ));
    }

    // 수정할 데이터가 있는 경우에만 검증
    if (administrator.name != null || 
        administrator.email != null || 
        administrator.phone != null || 
        administrator.mobile != null) {
      
      // 현재 데이터 조회 (검증용)
      final currentResult = await _repository.getAdministratorById(id);
      return currentResult.fold(
        (failure) => Left(failure),
        (current) async {
          // 새로운 값들로 검증
          final newName = administrator.name ?? current.name;
          final newEmail = administrator.email ?? current.email;
          final newPhone = administrator.phone ?? current.phone;
          final newMobile = administrator.mobile ?? current.mobile;

          final validationResult = await validateAdministratorData(
            newName,
            newEmail,
            newPhone,
            newMobile,
          );

          return validationResult.fold(
            (failure) => Left(failure),
            (isValid) async {
              if (!isValid) {
                return Left(ValidationFailure(
                  message: '관리자 정보가 유효하지 않습니다.',
                ));
              }

              // 이메일이 변경된 경우 중복 검사
              if (administrator.email != null && administrator.email != current.email) {
                final duplicateResult = await checkEmailDuplicate(
                  administrator.email!,
                  excludeId: id,
                );
                return duplicateResult.fold(
                  (failure) => Left(failure),
                  (isDuplicate) async {
                    if (isDuplicate) {
                      return Left(DuplicateFailure(
                        message: '이미 사용 중인 이메일 주소입니다.',
                      ));
                    }

                    return await _repository.updateAdministrator(id, administrator);
                  },
                );
              }

              return await _repository.updateAdministrator(id, administrator);
            },
          );
        },
      );
    }

    return await _repository.updateAdministrator(id, administrator);
  }

  @override
  Future<Either<Failure, void>> deleteAdministrator(int id) async {
    // 비즈니스 규칙: ID 유효성 검사
    if (id <= 0) {
      return Left(ValidationFailure(
        message: '유효하지 않은 관리자 ID입니다.',
      ));
    }

    // 비즈니스 로직: 관리자가 최소 1명은 남아있어야 함
    final administratorsResult = await _repository.getAdministrators(
      page: 1,
      pageSize: 5,
    );

    return administratorsResult.fold(
      (failure) => Left(failure),
      (administrators) async {
        if (administrators.totalCount <= 1) {
          return Left(ValidationFailure(
            message: '최소 1명의 관리자가 존재해야 합니다.',
          ));
        }

        return await _repository.deleteAdministrator(id);
      },
    );
  }

  @override
  Future<Either<Failure, bool>> checkEmailDuplicate(String email, {int? excludeId}) async {
    // 이메일 형식 검증
    if (!_isValidEmail(email)) {
      return Left(ValidationFailure(
        message: '유효하지 않은 이메일 형식입니다.',
      ));
    }

    return await _repository.isDuplicateEmail(email, excludeId: excludeId);
  }

  @override
  Future<Either<Failure, AdministratorDto>> authenticateAdministrator(
    String email,
    String password,
  ) async {
    // 입력값 검증
    if (email.trim().isEmpty || password.isEmpty) {
      return Left(ValidationFailure(
        message: '이메일과 비밀번호를 입력해주세요.',
      ));
    }

    if (!_isValidEmail(email)) {
      return Left(ValidationFailure(
        message: '유효하지 않은 이메일 형식입니다.',
      ));
    }

    return await _repository.authenticateAdministrator(email, password);
  }

  @override
  Future<Either<Failure, bool>> validateAdministratorData(
    String name,
    String email,
    String phone,
    String mobile,
  ) async {
    // 필수 필드 검증
    if (name.trim().isEmpty) {
      return Left(ValidationFailure(
        message: '관리자 이름을 입력해주세요.',
      ));
    }

    if (email.trim().isEmpty) {
      return Left(ValidationFailure(
        message: '이메일 주소를 입력해주세요.',
      ));
    }

    if (phone.trim().isEmpty) {
      return Left(ValidationFailure(
        message: '전화번호를 입력해주세요.',
      ));
    }

    if (mobile.trim().isEmpty) {
      return Left(ValidationFailure(
        message: '휴대폰 번호를 입력해주세요.',
      ));
    }

    // 이메일 형식 검증
    if (!_isValidEmail(email)) {
      return Left(ValidationFailure(
        message: '유효하지 않은 이메일 형식입니다.',
      ));
    }

    // 이름 길이 검증
    if (name.length > 100) {
      return Left(ValidationFailure(
        message: '관리자 이름은 100자 이내로 입력해주세요.',
      ));
    }

    // 전화번호 형식 검증 (숫자, 하이픈, 공백만 허용)
    if (!_isValidPhoneNumber(phone)) {
      return Left(ValidationFailure(
        message: '유효하지 않은 전화번호 형식입니다.',
      ));
    }

    if (!_isValidPhoneNumber(mobile)) {
      return Left(ValidationFailure(
        message: '유효하지 않은 휴대폰 번호 형식입니다.',
      ));
    }

    return const Right(true);
  }

  /// 이메일 형식 검증 (간단한 정규식)
  bool _isValidEmail(String email) {
    return RegExp(r'^[^\s@]+@[^\s@]+\.[^\s@]+$').hasMatch(email.trim());
  }

  /// 전화번호 형식 검증 (한국 형식 기준)
  bool _isValidPhoneNumber(String phone) {
    final cleaned = phone.replaceAll(RegExp(r'[\s\-\(\)]'), '');
    return RegExp(r'^\d{8,11}$').hasMatch(cleaned);
  }
}