import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';

/// 서비스 정보를 담는 데이터 클래스
class ServiceInfo {
  final String serviceId;
  final String serviceName;
  final String? serviceUrl;
  final String? cancellationUrl;
  final String categoryId;
  final String categoryNameKr;
  final String categoryNameEn;
  
  ServiceInfo({
    required this.serviceId,
    required this.serviceName,
    this.serviceUrl,
    this.cancellationUrl,
    required this.categoryId,
    required this.categoryNameKr,
    required this.categoryNameEn,
  });
}

/// 구독 서비스와 웹사이트 URL 매칭을 처리하는 서비스 클래스
class SubscriptionUrlMatcher {
  static Map<String, dynamic>? _servicesData;
  static bool _isInitialized = false;
  
  // 레거시 데이터 (JSON 로드 실패시 폴백)
  // OTT 서비스
  static final Map<String, String> ottServices = {
    'netflix': 'https://www.netflix.com',
    '넷플릭스': 'https://www.netflix.com',
    'disney+': 'https://www.disneyplus.com',
    '디즈니플러스': 'https://www.disneyplus.com',
    'youtube premium': 'https://www.youtube.com/premium',
    '유튜브 프리미엄': 'https://www.youtube.com/premium',
    'watcha': 'https://watcha.com',
    '왓챠': 'https://watcha.com',
    'wavve': 'https://www.wavve.com',
    '웨이브': 'https://www.wavve.com',
    'apple tv+': 'https://tv.apple.com',
    '애플 티비플러스': 'https://tv.apple.com',
    'tving': 'https://www.tving.com',
    '티빙': 'https://www.tving.com',
    'prime video': 'https://www.primevideo.com',
    '프라임 비디오': 'https://www.primevideo.com',
    'amazon prime': 'https://www.amazon.com/prime',
    '아마존 프라임': 'https://www.amazon.com/prime',
    'coupang play': 'https://play.coupangplay.com',
    '쿠팡 플레이': 'https://play.coupangplay.com',
    'hulu': 'https://www.hulu.com',
    '훌루': 'https://www.hulu.com',
  };

  // 음악 서비스
  static final Map<String, String> musicServices = {
    'spotify': 'https://www.spotify.com',
    '스포티파이': 'https://www.spotify.com',
    'apple music': 'https://music.apple.com',
    '애플 뮤직': 'https://music.apple.com',
    'melon': 'https://www.melon.com',
    '멜론': 'https://www.melon.com',
    'genie': 'https://www.genie.co.kr',
    '지니': 'https://www.genie.co.kr',
    'youtube music': 'https://music.youtube.com',
    '유튜브 뮤직': 'https://music.youtube.com',
    'bugs': 'https://music.bugs.co.kr',
    '벅스': 'https://music.bugs.co.kr',
    'flo': 'https://www.music-flo.com',
    '플로': 'https://www.music-flo.com',
    'vibe': 'https://vibe.naver.com',
    '바이브': 'https://vibe.naver.com',
    'tidal': 'https://www.tidal.com',
    '타이달': 'https://www.tidal.com',
  };

  // 저장 (클라우드/파일) 서비스
  static final Map<String, String> storageServices = {
    'google drive': 'https://www.google.com/drive/',
    '구글 드라이브': 'https://www.google.com/drive/',
    'dropbox': 'https://www.dropbox.com',
    '드롭박스': 'https://www.dropbox.com',
    'onedrive': 'https://www.onedrive.com',
    '원드라이브': 'https://www.onedrive.com',
    'icloud': 'https://www.icloud.com',
    '아이클라우드': 'https://www.icloud.com',
    'box': 'https://www.box.com',
    '박스': 'https://www.box.com',
    'pcloud': 'https://www.pcloud.com',
    'mega': 'https://mega.nz',
    '메가': 'https://mega.nz',
    'naver mybox': 'https://mybox.naver.com',
    '네이버 마이박스': 'https://mybox.naver.com',
  };

  // 통신 · 인터넷 · TV 서비스
  static final Map<String, String> telecomServices = {
    'skt': 'https://www.sktelecom.com',
    'sk텔레콤': 'https://www.sktelecom.com',
    'kt': 'https://www.kt.com',
    'lgu+': 'https://www.lguplus.com',
    'lg유플러스': 'https://www.lguplus.com',
    'olleh tv': 'https://www.kt.com/olleh_tv',
    '올레 tv': 'https://www.kt.com/olleh_tv',
    'b tv': 'https://www.skbroadband.com',
    '비티비': 'https://www.skbroadband.com',
    'u+모바일tv': 'https://www.lguplus.com',
    '유플러스모바일tv': 'https://www.lguplus.com',
  };

  // 생활/라이프스타일 서비스
  static final Map<String, String> lifestyleServices = {
    '네이버 플러스': 'https://plus.naver.com',
    'naver plus': 'https://plus.naver.com',
    '카카오 구독': 'https://subscribe.kakao.com',
    'kakao subscribe': 'https://subscribe.kakao.com',
    '쿠팡 와우': 'https://www.coupang.com/np/coupangplus',
    'coupang wow': 'https://www.coupang.com/np/coupangplus',
    '스타벅스 버디': 'https://www.starbucks.co.kr',
    'starbucks buddy': 'https://www.starbucks.co.kr',
    'cu 구독': 'https://cu.bgfretail.com',
    'gs25 구독': 'https://gs25.gsretail.com',
    '현대차 구독': 'https://www.hyundai.com/kr/ko/eco/vehicle-subscription',
    'lg전자 구독': 'https://www.lge.co.kr',
    '삼성전자 구독': 'https://www.samsung.com/sec',
    '다이슨 케어': 'https://www.dyson.co.kr',
    'dyson care': 'https://www.dyson.co.kr',
    '마켓컬리': 'https://www.kurly.com',
    'kurly': 'https://www.kurly.com',
    '헬로네이처': 'https://www.hellonature.com',
    'hello nature': 'https://www.hellonature.com',
    '이마트 트레이더스': 'https://www.emarttraders.co.kr',
    '홈플러스': 'https://www.homeplus.co.kr',
    'hellofresh': 'https://www.hellofresh.com',
    '헬로프레시': 'https://www.hellofresh.com',
    'bespoke post': 'https://www.bespokepost.com',
  };

  // 쇼핑/이커머스 서비스
  static final Map<String, String> shoppingServices = {
    'amazon prime': 'https://www.amazon.com/prime',
    '아마존 프라임': 'https://www.amazon.com/prime',
    'walmart+': 'https://www.walmart.com/plus',
    '월마트플러스': 'https://www.walmart.com/plus',
    'chewy': 'https://www.chewy.com',
    '츄이': 'https://www.chewy.com',
    'dollar shave club': 'https://www.dollarshaveclub.com',
    '달러셰이브클럽': 'https://www.dollarshaveclub.com',
    'instacart': 'https://www.instacart.com',
    '인스타카트': 'https://www.instacart.com',
    'shipt': 'https://www.shipt.com',
    '십트': 'https://www.shipt.com',
    'grove': 'https://grove.co',
    '그로브': 'https://grove.co',
    'cratejoy': 'https://www.cratejoy.com',
    'shopify': 'https://www.shopify.com',
    '쇼피파이': 'https://www.shopify.com',
  };

  // AI 서비스
  static final Map<String, String> aiServices = {
    'chatgpt': 'https://chat.openai.com',
    '챗GPT': 'https://chat.openai.com',
    'openai': 'https://openai.com',
    '오픈AI': 'https://openai.com',
    'claude': 'https://claude.ai',
    '클로드': 'https://claude.ai',
    'anthropic': 'https://www.anthropic.com',
    '앤트로픽': 'https://www.anthropic.com',
    'midjourney': 'https://www.midjourney.com',
    '미드저니': 'https://www.midjourney.com',
    'perplexity': 'https://www.perplexity.ai',
    '퍼플렉시티': 'https://www.perplexity.ai',
    'copilot': 'https://copilot.microsoft.com',
    '코파일럿': 'https://copilot.microsoft.com',
    'gemini': 'https://gemini.google.com',
    '제미니': 'https://gemini.google.com',
    'google ai': 'https://ai.google',
    '구글 AI': 'https://ai.google',
    'bard': 'https://bard.google.com',
    '바드': 'https://bard.google.com',
    'dall-e': 'https://openai.com/dall-e',
    '달리': 'https://openai.com/dall-e',
    'stable diffusion': 'https://stability.ai',
    '스테이블 디퓨전': 'https://stability.ai',
  };

  // 프로그래밍 / 개발 서비스
  static final Map<String, String> programmingServices = {
    'github': 'https://github.com',
    '깃허브': 'https://github.com',
    'cursor': 'https://cursor.com',
    '커서': 'https://cursor.com',
    'jetbrains': 'https://www.jetbrains.com',
    '제트브레인스': 'https://www.jetbrains.com',
    'intellij': 'https://www.jetbrains.com/idea',
    '인텔리제이': 'https://www.jetbrains.com/idea',
    'visual studio': 'https://visualstudio.microsoft.com',
    '비주얼 스튜디오': 'https://visualstudio.microsoft.com',
    'aws': 'https://aws.amazon.com',
    '아마존 웹서비스': 'https://aws.amazon.com',
    'azure': 'https://azure.microsoft.com',
    '애저': 'https://azure.microsoft.com',
    'google cloud': 'https://cloud.google.com',
    '구글 클라우드': 'https://cloud.google.com',
    'digitalocean': 'https://www.digitalocean.com',
    '디지털오션': 'https://www.digitalocean.com',
    'heroku': 'https://www.heroku.com',
    '헤로쿠': 'https://www.heroku.com',
    'codecademy': 'https://www.codecademy.com',
    '코드아카데미': 'https://www.codecademy.com',
    'udemy': 'https://www.udemy.com',
    '유데미': 'https://www.udemy.com',
    'coursera': 'https://www.coursera.org',
    '코세라': 'https://www.coursera.org',
  };

  // 오피스 및 협업 툴
  static final Map<String, String> officeTools = {
    'microsoft 365': 'https://www.microsoft.com/microsoft-365',
    '마이크로소프트 365': 'https://www.microsoft.com/microsoft-365',
    'office 365': 'https://www.microsoft.com/microsoft-365',
    '오피스 365': 'https://www.microsoft.com/microsoft-365',
    'google workspace': 'https://workspace.google.com',
    '구글 워크스페이스': 'https://workspace.google.com',
    'slack': 'https://slack.com',
    '슬랙': 'https://slack.com',
    'notion': 'https://www.notion.so',
    '노션': 'https://www.notion.so',
    'trello': 'https://trello.com',
    '트렐로': 'https://trello.com',
    'asana': 'https://asana.com',
    '아사나': 'https://asana.com',
    'dropbox': 'https://www.dropbox.com',
    '드롭박스': 'https://www.dropbox.com',
    'figma': 'https://www.figma.com',
    '피그마': 'https://www.figma.com',
    'adobe creative cloud': 'https://www.adobe.com/creativecloud.html',
    '어도비 크리에이티브 클라우드': 'https://www.adobe.com/creativecloud.html',
  };

  // 기타 유명 서비스
  static final Map<String, String> otherServices = {
    'google one': 'https://one.google.com',
    '구글 원': 'https://one.google.com',
    'icloud': 'https://www.icloud.com',
    '아이클라우드': 'https://www.icloud.com',
    'nintendo switch online': 'https://www.nintendo.com/switch/online-service',
    '닌텐도 스위치 온라인': 'https://www.nintendo.com/switch/online-service',
    'playstation plus': 'https://www.playstation.com/ps-plus',
    '플레이스테이션 플러스': 'https://www.playstation.com/ps-plus',
    'xbox game pass': 'https://www.xbox.com/xbox-game-pass',
    '엑스박스 게임 패스': 'https://www.xbox.com/xbox-game-pass',
    'ea play': 'https://www.ea.com/ea-play',
    'EA 플레이': 'https://www.ea.com/ea-play',
    'ubisoft+': 'https://ubisoft.com/plus',
    '유비소프트+': 'https://ubisoft.com/plus',
    'epic games': 'https://www.epicgames.com',
    '에픽 게임즈': 'https://www.epicgames.com',
    'steam': 'https://store.steampowered.com',
    '스팀': 'https://store.steampowered.com',
  };

  // 해지 안내 페이지 URL 목록 (공식 해지 안내 페이지가 있는 서비스들)
  static final Map<String, String> cancellationUrls = {
    // OTT 서비스 해지 안내 페이지
    'netflix': 'https://help.netflix.com/ko/node/407',
    '넷플릭스': 'https://help.netflix.com/ko/node/407',
    'disney+':
        'https://help.disneyplus.com/csp?id=csp_article_content&sys_kb_id=f0ddbe01db7601105d5e040ad3961979',
    '디즈니플러스':
        'https://help.disneyplus.com/csp?id=csp_article_content&sys_kb_id=f0ddbe01db7601105d5e040ad3961979',
    'youtube premium': 'https://support.google.com/youtube/answer/6308278',
    '유튜브 프리미엄': 'https://support.google.com/youtube/answer/6308278',
    'watcha': 'https://watcha.com/settings/payment',
    '왓챠': 'https://watcha.com/settings/payment',
    'wavve': 'https://www.wavve.com/my',
    '웨이브': 'https://www.wavve.com/my',
    'apple tv+': 'https://support.apple.com/ko-kr/HT202039',
    '애플 티비플러스': 'https://support.apple.com/ko-kr/HT202039',
    'tving': 'https://www.tving.com/my/cancelMembership',
    '티빙': 'https://www.tving.com/my/cancelMembership',
    'amazon prime': 'https://www.amazon.com/gp/primecentral/managemembership',
    '아마존 프라임': 'https://www.amazon.com/gp/primecentral/managemembership',

    // 음악 서비스 해지 안내 페이지
    'spotify': 'https://support.spotify.com/us/article/cancel-premium/',
    '스포티파이': 'https://support.spotify.com/us/article/cancel-premium/',
    'apple music': 'https://support.apple.com/ko-kr/HT202039',
    '애플 뮤직': 'https://support.apple.com/ko-kr/HT202039',
    'melon':
        'https://faqs2.melon.com/customer/faq/informFaq.htm?no=17&faqId=QUES20150209000002&orderChk=date&SEARCH_KEY=&SEARCH_PAR_CATEGORY=CATE20130909000006&SEARCH_CATEGORY=CATE20130909000021',
    '멜론':
        'https://faqs2.melon.com/customer/faq/informFaq.htm?no=17&faqId=QUES20150209000002&orderChk=date&SEARCH_KEY=&SEARCH_PAR_CATEGORY=CATE20130909000006&SEARCH_CATEGORY=CATE20130909000021',
    'youtube music': 'https://support.google.com/youtubemusic/answer/6308278',
    '유튜브 뮤직': 'https://support.google.com/youtubemusic/answer/6308278',

    // AI 서비스 해지 안내 페이지
    'chatgpt':
        'https://help.openai.com/en/articles/7730211-manage-or-cancel-your-chatgpt-plus-subscription',
    '챗GPT':
        'https://help.openai.com/en/articles/7730211-manage-or-cancel-your-chatgpt-plus-subscription',
    'claude':
        'https://help.anthropic.com/en/articles/8798313-how-do-i-cancel-my-claude-subscription',
    '클로드':
        'https://help.anthropic.com/en/articles/8798313-how-do-i-cancel-my-claude-subscription',
    'midjourney': 'https://docs.midjourney.com/docs/manage-subscription',
    '미드저니': 'https://docs.midjourney.com/docs/manage-subscription',

    // 프로그래밍 / 개발 서비스 해지 안내 페이지
    'github':
        'https://docs.github.com/ko/billing/managing-billing-for-your-github-account/downgrading-your-github-subscription',
    '깃허브':
        'https://docs.github.com/ko/billing/managing-billing-for-your-github-account/downgrading-your-github-subscription',
    'jetbrains':
        'https://sales.jetbrains.com/hc/en-gb/articles/207240845-How-to-cancel-an-auto-renewal-subscription-',
    '제트브레인스':
        'https://sales.jetbrains.com/hc/en-gb/articles/207240845-How-to-cancel-an-auto-renewal-subscription-',

    // 오피스 및 협업 툴 해지 안내 페이지
    'microsoft 365':
        'https://support.microsoft.com/en-us/office/cancel-a-microsoft-365-subscription-46e2634c-c64b-4c65-94b9-2cc9c960e91b',
    '마이크로소프트 365':
        'https://support.microsoft.com/en-us/office/cancel-a-microsoft-365-subscription-46e2634c-c64b-4c65-94b9-2cc9c960e91b',
    'office 365':
        'https://support.microsoft.com/en-us/office/cancel-a-microsoft-365-subscription-46e2634c-c64b-4c65-94b9-2cc9c960e91b',
    '오피스 365':
        'https://support.microsoft.com/en-us/office/cancel-a-microsoft-365-subscription-46e2634c-c64b-4c65-94b9-2cc9c960e91b',
    'slack':
        'https://slack.com/help/articles/360003378691-Cancel-your-Slack-subscription',
    '슬랙':
        'https://slack.com/help/articles/360003378691-Cancel-your-Slack-subscription',
    'notion':
        'https://www.notion.so/help/billing-and-payment-settings#cancel-a-subscription',
    '노션':
        'https://www.notion.so/help/billing-and-payment-settings#cancel-a-subscription',
    'dropbox': 'https://help.dropbox.com/accounts-billing/cancellation',
    '드롭박스': 'https://help.dropbox.com/accounts-billing/cancellation',
    'adobe creative cloud':
        'https://helpx.adobe.com/manage-account/using/cancel-subscription.html',
    '어도비 크리에이티브 클라우드':
        'https://helpx.adobe.com/manage-account/using/cancel-subscription.html',

    // 기타 유명 서비스 해지 안내 페이지
    'google one': 'https://support.google.com/googleone/answer/9140429',
    '구글 원': 'https://support.google.com/googleone/answer/9140429',
    'icloud': 'https://support.apple.com/ko-kr/HT207594',
    '아이클라우드': 'https://support.apple.com/ko-kr/HT207594',
    'nintendo switch online':
        'https://en-americas-support.nintendo.com/app/answers/detail/a_id/41925/~/how-to-cancel-a-nintendo-switch-online-membership',
    '닌텐도 스위치 온라인':
        'https://en-americas-support.nintendo.com/app/answers/detail/a_id/41925/~/how-to-cancel-a-nintendo-switch-online-membership',
    'playstation plus':
        'https://www.playstation.com/support/subscriptions/cancel-playstation-plus/',
    '플레이스테이션 플러스':
        'https://www.playstation.com/support/subscriptions/cancel-playstation-plus/',
    'xbox game pass':
        'https://support.xbox.com/help/subscriptions-billing/manage-subscriptions/xbox-game-pass-how-to-cancel',
    '엑스박스 게임 패스':
        'https://support.xbox.com/help/subscriptions-billing/manage-subscriptions/xbox-game-pass-how-to-cancel',
  };

  // 모든 서비스 매핑을 합친 맵
  static final Map<String, String> allServices = {
    ...ottServices,
    ...musicServices,
    ...storageServices,
    ...aiServices,
    ...programmingServices,
    ...officeTools,
    ...lifestyleServices,
    ...shoppingServices,
    ...telecomServices,
    ...otherServices,
  };
  
  /// JSON 데이터 초기화
  static Future<void> initialize() async {
    if (_isInitialized) return;
    
    try {
      final jsonString = await rootBundle.loadString('assets/data/subscription_services.json');
      _servicesData = json.decode(jsonString);
      _isInitialized = true;
      print('SubscriptionUrlMatcher: JSON 데이터 로드 완료');
    } catch (e) {
      print('SubscriptionUrlMatcher: JSON 로드 실패 - $e');
      // 로드 실패시 기존 하드코딩 데이터 사용
      _isInitialized = true;
    }
  }
  
  /// 도메인 추출 (www와 TLD 제외)
  static 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) {
      print('SubscriptionUrlMatcher: 도메인 추출 실패 - $e');
      return null;
    }
  }
  
  /// URL로 서비스 찾기
  static Future<ServiceInfo?> findServiceByUrl(String url) async {
    await initialize();
    
    final domain = extractDomain(url);
    if (domain == null) return null;
    
    // JSON 데이터가 있으면 JSON에서 찾기
    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: _getCategoryIdByKey(categoryId),
                categoryNameKr: categoryData['nameKr'] ?? '',
                categoryNameEn: categoryData['nameEn'] ?? '',
              );
            }
          }
        }
      }
    }
    
    // JSON에서 못 찾았으면 레거시 방식으로 찾기
    for (final entry in 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: _getCategoryForLegacyService(entry.key),
          categoryNameKr: '',
          categoryNameEn: '',
        );
      }
    }
    
    return null;
  }
  
  /// 서비스명으로 URL 찾기 (기존 suggestUrl 메서드 유지)
  static String? suggestUrl(String serviceName) {
    if (serviceName.isEmpty) {
      print('SubscriptionUrlMatcher: 빈 serviceName');
      return null;
    }

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

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

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

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

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

      // 개발 서비스 검사
      for (final entry in programmingServices.entries) {
        if (lowerName.contains(entry.key.toLowerCase())) {
          print(
              'SubscriptionUrlMatcher: 개발 서비스 매칭 - $lowerName -> ${entry.key}');
          return entry.value;
        }
      }

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

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

      // 유사한 이름 검사 (퍼지 매칭) - 단어 기반으로 검색
      for (final entry in allServices.entries) {
        final serviceWords = lowerName.split(' ');
        final keyWords = entry.key.toLowerCase().split(' ');

        // 단어 단위로 일치하는지 확인
        for (final word in serviceWords) {
          if (word.length > 2 &&
              keyWords.any((keyWord) => keyWord.contains(word))) {
            print(
                'SubscriptionUrlMatcher: 단어 기반 매칭 - $word (in $lowerName) -> ${entry.key}');
            return entry.value;
          }
        }
      }

      // 추출 가능한 도메인이 있는지 확인
      final domainMatch = RegExp(r'(\w+)').firstMatch(lowerName);
      if (domainMatch != null && domainMatch.group(1)!.length > 2) {
        final domain = domainMatch.group(1)!.trim();
        if (domain.length > 2 &&
            !['the', 'and', 'for', 'www'].contains(domain)) {
          final url = 'https://www.$domain.com';
          print('SubscriptionUrlMatcher: 도메인 추출 - $lowerName -> $url');
          return url;
        }
      }

      print('SubscriptionUrlMatcher: 매칭 실패 - $lowerName');
      return null;
    } catch (e) {
      print('SubscriptionUrlMatcher: URL 매칭 중 오류 발생: $e');
      return null;
    }
  }
  
  /// 해지 안내 URL 찾기 (개선된 버전)
  static Future<String?> findCancellationUrl({
    String? serviceName,
    String? websiteUrl,
    String locale = 'kr',
  }) async {
    await initialize();
    
    // JSON 데이터가 있으면 JSON에서 찾기
    if (_servicesData != null) {
      final categories = _servicesData!['categories'] as Map<String, dynamic>;
      
      // 1. 서비스명으로 찾기
      if (serviceName != null && serviceName.isNotEmpty) {
        final lowerName = serviceName.toLowerCase().trim();
        
        for (final categoryData in categories.values) {
          final services = (categoryData as Map<String, dynamic>)['services'] as Map<String, dynamic>;
          
          for (final serviceData in services.values) {
            final names = List<String>.from((serviceData as Map<String, dynamic>)['names'] ?? []);
            
            for (final name in names) {
              if (lowerName.contains(name.toLowerCase()) || name.toLowerCase().contains(lowerName)) {
                final cancellationUrls = serviceData['cancellationUrls'] as Map<String, dynamic>?;
                if (cancellationUrls != null) {
                  // 요청한 언어의 URL이 있으면 반환, 없으면 다른 언어 URL 반환
                  return cancellationUrls[locale] ?? 
                         cancellationUrls[locale == 'kr' ? 'en' : 'kr'];
                }
              }
            }
          }
        }
      }
      
      // 2. URL로 찾기
      if (websiteUrl != null && websiteUrl.isNotEmpty) {
        final domain = extractDomain(websiteUrl);
        if (domain != null) {
          for (final categoryData in categories.values) {
            final services = (categoryData as Map<String, dynamic>)['services'] as Map<String, dynamic>;
            
            for (final serviceData in services.values) {
              final domains = List<String>.from((serviceData as Map<String, dynamic>)['domains'] ?? []);
              
              for (final serviceDomain in domains) {
                if (domain.contains(serviceDomain) || serviceDomain.contains(domain)) {
                  final cancellationUrls = serviceData['cancellationUrls'] as Map<String, dynamic>?;
                  if (cancellationUrls != null) {
                    return cancellationUrls[locale] ?? 
                           cancellationUrls[locale == 'kr' ? 'en' : 'kr'];
                  }
                }
              }
            }
          }
        }
      }
    }
    
    // JSON에서 못 찾았으면 레거시 방식으로 찾기
    return _findCancellationUrlLegacy(serviceName ?? websiteUrl ?? '');
  }

  /// 서비스명 또는 웹사이트 URL을 기반으로 해지 안내 페이지 URL 찾기 (레거시)
  static String? _findCancellationUrlLegacy(String serviceNameOrUrl) {
    if (serviceNameOrUrl.isEmpty) {
      return null;
    }

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

    // 직접 서비스명으로 찾기
    if (cancellationUrls.containsKey(lowerText)) {
      return cancellationUrls[lowerText];
    }

    // 서비스명에 부분 포함으로 찾기
    for (var entry in cancellationUrls.entries) {
      final String key = entry.key.toLowerCase();
      if (lowerText.contains(key) || key.contains(lowerText)) {
        return entry.value;
      }
    }

    // URL을 통해 서비스명 추출 후 찾기
    if (lowerText.startsWith('http')) {
      // URL 도메인 추출 (https://www.netflix.com 에서 netflix 추출)
      final domainRegex = RegExp(r'https?://(?:www\.)?([a-zA-Z0-9-]+)');
      final match = domainRegex.firstMatch(lowerText);

      if (match != null && match.groupCount >= 1) {
        final domain = match.group(1)?.toLowerCase() ?? '';

        // 도메인으로 서비스명 찾기
        for (var entry in cancellationUrls.entries) {
          if (entry.key.toLowerCase().contains(domain)) {
            return entry.value;
          }
        }
      }
    }

    // 해지 안내 페이지를 찾지 못함
    return null;
  }

  /// 서비스에 공식 해지 안내 페이지가 있는지 확인
  static Future<bool> hasCancellationPage(String serviceNameOrUrl) async {
    // 새로운 JSON 기반 방식으로 확인
    final cancellationUrl = await findCancellationUrl(
      serviceName: serviceNameOrUrl,
      websiteUrl: serviceNameOrUrl,
    );
    return cancellationUrl != null;
  }
  
  /// 서비스명으로 카테고리 찾기
  static Future<String?> findCategoryByServiceName(String serviceName) async {
    await initialize();
    if (serviceName.isEmpty) return null;
    
    final lowerName = serviceName.toLowerCase().trim();
    
    // JSON 데이터가 있으면 JSON에서 찾기
    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 serviceData in services.values) {
          final names = List<String>.from((serviceData as Map<String, dynamic>)['names'] ?? []);
          
          for (final name in names) {
            if (lowerName.contains(name.toLowerCase()) || name.toLowerCase().contains(lowerName)) {
              return _getCategoryIdByKey(categoryId);
            }
          }
        }
      }
    }
    
    // JSON에서 못 찾았으면 레거시 방식으로 카테고리 추측
    return _getCategoryForLegacyService(serviceName);
  }
  
  /// 현재 로케일에 따라 서비스 표시명 가져오기
  static Future<String> getServiceDisplayName({
    required String serviceName,
    required String locale,
  }) async {
    await initialize();
    
    if (_servicesData == null) {
      return serviceName;
    }
    
    final lowerName = serviceName.toLowerCase().trim();
    final categories = _servicesData!['categories'] as Map<String, dynamic>;
    
    // JSON에서 서비스 찾기
    for (final categoryData in categories.values) {
      final services = (categoryData as Map<String, dynamic>)['services'] as Map<String, dynamic>;
      
      for (final serviceData in services.values) {
        final data = serviceData as Map<String, dynamic>;
        final names = List<String>.from(data['names'] ?? []);
        
        // names 배열에 있는지 확인
        for (final name in names) {
          if (lowerName == name.toLowerCase() || 
              lowerName.contains(name.toLowerCase()) || 
              name.toLowerCase().contains(lowerName)) {
            // 로케일에 따라 적절한 이름 반환
            if (locale == 'ko' || locale == 'kr') {
              return data['nameKr'] ?? serviceName;
            } else {
              return data['nameEn'] ?? serviceName;
            }
          }
        }
        
        // nameKr/nameEn에 직접 매칭 확인
        final nameKr = (data['nameKr'] ?? '').toString().toLowerCase();
        final nameEn = (data['nameEn'] ?? '').toString().toLowerCase();
        
        if (lowerName == nameKr || lowerName == nameEn) {
          if (locale == 'ko' || locale == 'kr') {
            return data['nameKr'] ?? serviceName;
          } else {
            return data['nameEn'] ?? serviceName;
          }
        }
      }
    }
    
    // 찾지 못한 경우 원래 이름 반환
    return serviceName;
  }
  
  /// 카테고리 키를 실제 카테고리 ID로 매핑
  static String _getCategoryIdByKey(String key) {
    // 여기에 실제 앱의 카테고리 ID 매핑을 추가
    // 임시로 카테고리명 기반 매핑
    switch (key) {
      case 'music':
        return 'music_streaming';
      case 'ott':
        return 'ott_services';
      case 'storage':
        return 'cloud_storage';
      case 'ai':
        return 'ai_services';
      case 'programming':
        return 'dev_tools';
      case 'office':
        return 'office_tools';
      case 'lifestyle':
        return 'lifestyle';
      case 'shopping':
        return 'shopping';
      case 'gaming':
        return 'gaming';
      case 'telecom':
        return 'telecom';
      default:
        return 'other';
    }
  }
  
  /// 레거시 서비스명으로 카테고리 추측
  static String _getCategoryForLegacyService(String serviceName) {
    final lowerName = serviceName.toLowerCase();
    
    if (ottServices.containsKey(lowerName)) return 'ott_services';
    if (musicServices.containsKey(lowerName)) return 'music_streaming';
    if (storageServices.containsKey(lowerName)) return 'cloud_storage';
    if (aiServices.containsKey(lowerName)) return 'ai_services';
    if (programmingServices.containsKey(lowerName)) return 'dev_tools';
    if (officeTools.containsKey(lowerName)) return 'office_tools';
    if (lifestyleServices.containsKey(lowerName)) return 'lifestyle';
    if (shoppingServices.containsKey(lowerName)) return 'shopping';
    if (telecomServices.containsKey(lowerName)) return 'telecom';
    
    return 'other';
  }
  
  /// SMS에서 URL과 서비스 정보 추출
  static Future<ServiceInfo?> extractServiceFromSms(String smsText) async {
    await initialize();
    
    // URL 패턴 찾기
    final urlPattern = RegExp(
      r'https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)',
      caseSensitive: false,
    );
    
    final matches = urlPattern.allMatches(smsText);
    
    for (final match in matches) {
      final url = match.group(0);
      if (url != null) {
        final serviceInfo = await findServiceByUrl(url);
        if (serviceInfo != null) {
          return serviceInfo;
        }
      }
    }
    
    // URL로 못 찾았으면 서비스명으로 시도
    final lowerSms = smsText.toLowerCase();
    
    // 모든 서비스명 검사
    for (final entry in allServices.entries) {
      if (lowerSms.contains(entry.key.toLowerCase())) {
        final categoryId = await findCategoryByServiceName(entry.key) ?? 'other';
        
        return ServiceInfo(
          serviceId: entry.key,
          serviceName: entry.key,
          serviceUrl: entry.value,
          cancellationUrl: null,
          categoryId: categoryId,
          categoryNameKr: '',
          categoryNameEn: '',
        );
      }
    }
    
    return null;
  }
  
  /// URL이 알려진 서비스 URL인지 확인
  static Future<bool> isKnownServiceUrl(String url) async {
    final serviceInfo = await findServiceByUrl(url);
    return serviceInfo != null;
  }

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

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

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

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

      for (var entry in 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;
  }
}