import '../models/service_info.dart';
import '../data/service_data_repository.dart';
import '../data/legacy_service_data.dart';
import 'category_mapper_service.dart';
import '../../../utils/logger.dart';

/// URL 매칭 관련 기능을 제공하는 서비스 클래스
class UrlMatcherService {
  final ServiceDataRepository _dataRepository;
  final CategoryMapperService _categoryMapper;

  UrlMatcherService(this._dataRepository, this._categoryMapper);

  /// 도메인 추출 (www와 TLD 제외)
  String? extractDomain(String url) {
    try {
      final uri = Uri.parse(url);
      final host = uri.host.toLowerCase();

      // 도메인 부분 추출
      var parts = host.split('.');

      // www 제거
      if (parts.isNotEmpty && parts[0] == 'www') {
        parts = parts.sublist(1);
      }

      // 서브도메인 처리 (예: music.youtube.com)
      if (parts.length >= 3) {
        // 서브도메인 포함 전체 도메인 반환
        return parts.sublist(0, parts.length - 1).join('.');
      } else if (parts.length >= 2) {
        // 메인 도메인만 반환
        return parts[0];
      }

      return null;
    } catch (e) {
      Log.e('UrlMatcherService: 도메인 추출 실패', e);
      return null;
    }
  }

  /// URL로 서비스 찾기
  Future<ServiceInfo?> findServiceByUrl(String url) async {
    final domain = extractDomain(url);
    if (domain == null) return null;

    // JSON 데이터가 있으면 JSON에서 찾기
    final servicesData = _dataRepository.getServicesData();
    if (servicesData != null) {
      final categories = servicesData['categories'] as Map<String, dynamic>;

      for (final categoryEntry in categories.entries) {
        final categoryId = categoryEntry.key;
        final categoryData = categoryEntry.value as Map<String, dynamic>;
        final services = categoryData['services'] as Map<String, dynamic>;

        for (final serviceEntry in services.entries) {
          final serviceId = serviceEntry.key;
          final serviceData = serviceEntry.value as Map<String, dynamic>;
          final domains = List<String>.from(serviceData['domains'] ?? []);

          // 도메인이 일치하는지 확인
          for (final serviceDomain in domains) {
            if (domain.contains(serviceDomain) ||
                serviceDomain.contains(domain)) {
              final names = List<String>.from(serviceData['names'] ?? []);
              final urls = serviceData['urls'] as Map<String, dynamic>?;

              return ServiceInfo(
                serviceId: serviceId,
                serviceName: names.isNotEmpty ? names[0] : serviceId,
                serviceUrl: urls?['kr'] ?? urls?['en'],
                cancellationUrl: null,
                categoryId: _categoryMapper.getCategoryIdByKey(categoryId),
                categoryNameKr: categoryData['nameKr'] ?? '',
                categoryNameEn: categoryData['nameEn'] ?? '',
              );
            }
          }
        }
      }
    }

    // JSON에서 못 찾았으면 레거시 방식으로 찾기
    for (final entry in LegacyServiceData.allServices.entries) {
      final serviceUrl = entry.value;
      final serviceDomain = extractDomain(serviceUrl);

      if (serviceDomain != null &&
          (domain.contains(serviceDomain) || serviceDomain.contains(domain))) {
        return ServiceInfo(
          serviceId: entry.key,
          serviceName: entry.key,
          serviceUrl: serviceUrl,
          cancellationUrl: null,
          categoryId: _categoryMapper.getCategoryForLegacyService(entry.key),
          categoryNameKr: '',
          categoryNameEn: '',
        );
      }
    }

    return null;
  }

  /// 서비스명으로 URL 찾기
  String? suggestUrl(String serviceName) {
    if (serviceName.isEmpty) {
      Log.w('UrlMatcherService: 빈 serviceName');
      return null;
    }

    // 소문자로 변환하여 비교
    final lowerName = serviceName.toLowerCase().trim();

    try {
      // 정확한 매칭을 먼저 시도
      for (final entry in LegacyServiceData.allServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: 정확한 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // OTT 서비스 검사
      for (final entry in LegacyServiceData.ottServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: OTT 서비스 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // 음악 서비스 검사
      for (final entry in LegacyServiceData.musicServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: 음악 서비스 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // AI 서비스 검사
      for (final entry in LegacyServiceData.aiServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: AI 서비스 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // 프로그래밍 서비스 검사
      for (final entry in LegacyServiceData.programmingServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: 프로그래밍 서비스 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // 오피스 툴 검사
      for (final entry in LegacyServiceData.officeTools.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: 오피스 툴 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // 기타 서비스 검사
      for (final entry in LegacyServiceData.otherServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          Log.d('UrlMatcherService: 기타 서비스 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      // 전체 서비스에서 부분 매칭 재시도
      for (final entry in LegacyServiceData.allServices.entries) {
        final key = entry.key.toLowerCase();
        if (key.contains(lowerName) || lowerName.contains(key)) {
          Log.d('UrlMatcherService: 부분 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

      Log.d('UrlMatcherService: 매칭 실패 - $lowerName');
      return null;
    } catch (e) {
      Log.e('UrlMatcherService: suggestUrl 에러', e);
      return null;
    }
  }

  /// URL이 알려진 서비스 URL인지 확인
  Future<bool> isKnownServiceUrl(String url) async {
    final serviceInfo = await findServiceByUrl(url);
    return serviceInfo != null;
  }

  /// 입력된 서비스 이름이나 문자열에서 매칭되는 URL을 찾아 반환
  String? findMatchingUrl(String text, {bool usePartialMatch = true}) {
    // 입력 텍스트가 비어있거나 null인 경우
    if (text.isEmpty) {
      return null;
    }

    // 소문자로 변환하여 처리
    final String lowerText = text.toLowerCase().trim();

    // 정확히 일치하는 경우
    if (LegacyServiceData.allServices.containsKey(lowerText)) {
      return LegacyServiceData.allServices[lowerText];
    }

    // 부분 일치 검색이 활성화된 경우
    if (usePartialMatch) {
      // 가장 긴 부분 매칭 찾기
      String? bestMatch;
      int maxLength = 0;

      for (var entry in LegacyServiceData.allServices.entries) {
        final String key = entry.key;

        // 입력된 텍스트에 서비스 키워드가 포함되어 있거나, 서비스 키워드에 입력된 텍스트가 포함된 경우
        if (lowerText.contains(key) || key.contains(lowerText)) {
          // 더 긴 매칭을 우선시
          if (key.length > maxLength) {
            maxLength = key.length;
            bestMatch = entry.value;
          }
        }
      }

      return bestMatch;
    }

    return null;
  }
}
