import 'package:flutter/services.dart';
import '../models/subscription_model.dart';
import '../temp/test_sms_data.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import '../services/subscription_url_matcher.dart';

class SmsScanner {
  Future<List<SubscriptionModel>> scanForSubscriptions() async {
    try {
      List<dynamic> smsList;
      print('SmsScanner: 스캔 시작');

      // 디버그 모드에서는 테스트 데이터 사용
      if (kDebugMode) {
        print('SmsScanner: 디버그 모드에서 테스트 데이터 사용');
        smsList = TestSmsData.getTestData();
        print('SmsScanner: 테스트 데이터 개수: ${smsList.length}');
      } else {
        print('SmsScanner: 실제 SMS 데이터 스캔');
        // 실제 환경에서는 네이티브 코드 호출
        const platform = MethodChannel('com.submanager/sms');
        try {
          smsList = await platform.invokeMethod('scanSubscriptions');
          print('SmsScanner: 네이티브 호출 성공, SMS 데이터 개수: ${smsList.length}');
        } catch (e) {
          print('SmsScanner: 네이티브 호출 실패: $e');
          // 오류 발생 시 빈 목록 반환
          return [];
        }
      }

      // SMS 데이터를 분석하여 반복 결제되는 구독 식별
      final List<SubscriptionModel> subscriptions = [];
      final Map<String, List<Map<String, dynamic>>> serviceGroups = {};

      // 서비스명별로 SMS 메시지 그룹화
      for (final sms in smsList) {
        final serviceName = sms['serviceName'] as String? ?? '알 수 없는 서비스';
        if (!serviceGroups.containsKey(serviceName)) {
          serviceGroups[serviceName] = [];
        }
        serviceGroups[serviceName]!.add(sms);
      }

      print('SmsScanner: 그룹화된 서비스 수: ${serviceGroups.length}');

      // 그룹화된 데이터로 구독 분석
      for (final entry in serviceGroups.entries) {
        print('SmsScanner: 서비스 "${entry.key}" - 메시지 개수: ${entry.value.length}');

        // 2회 이상 반복된 서비스만 구독으로 간주
        if (entry.value.length >= 2) {
          final serviceSms = entry.value[0]; // 가장 최근 SMS 사용
          final subscription = _parseSms(serviceSms, entry.value.length);
          if (subscription != null) {
            print(
                'SmsScanner: 구독 추가: ${subscription.serviceName}, 반복 횟수: ${subscription.repeatCount}');
            subscriptions.add(subscription);
          } else {
            print('SmsScanner: 구독 파싱 실패: ${entry.key}');
          }
        } else {
          print('SmsScanner: 반복 횟수 부족, 구독으로 간주하지 않음: ${entry.key}');
        }
      }

      print('SmsScanner: 최종 구독 개수: ${subscriptions.length}');
      return subscriptions;
    } catch (e) {
      print('SmsScanner: 예외 발생: $e');
      throw Exception('SMS 스캔 중 오류 발생: $e');
    }
  }

  SubscriptionModel? _parseSms(Map<String, dynamic> sms, int repeatCount) {
    try {
      final serviceName = sms['serviceName'] as String? ?? '알 수 없는 서비스';
      final monthlyCost = (sms['monthlyCost'] as num?)?.toDouble() ?? 0.0;
      final billingCycle = SubscriptionModel.normalizeBillingCycle(sms['billingCycle'] as String? ?? 'monthly');
      final nextBillingDateStr = sms['nextBillingDate'] as String?;
      // 실제 반복 횟수 사용 (테스트 데이터에서는 이미 제공됨)
      final actualRepeatCount = repeatCount > 0 ? repeatCount : 1;
      final message = sms['message'] as String? ?? '';

      // 통화 단위 감지 - 메시지 내용과 서비스명 모두 검사
      String currency = _detectCurrency(message);

      // 서비스명에 따라 통화 단위 재확인
      final dollarServices = [
        'GitHub',
        'GitHub Pro',
        'Netflix US',
        'Spotify',
        'Spotify Premium'
      ];
      if (dollarServices.any((service) => serviceName.contains(service))) {
        print('서비스명 $serviceName으로 USD 통화 단위 확정');
        currency = 'USD';
      }

      DateTime? nextBillingDate;
      if (nextBillingDateStr != null) {
        nextBillingDate = DateTime.tryParse(nextBillingDateStr);
      }

      DateTime? lastPaymentDate;
      final previousPaymentDateStr = sms['previousPaymentDate'] as String?;
      if (previousPaymentDateStr != null && previousPaymentDateStr.isNotEmpty) {
        lastPaymentDate = DateTime.tryParse(previousPaymentDateStr);
      }

      // 결제일 계산 로직 추가 - 미래 날짜가 아니면 조정
      DateTime adjustedNextBillingDate = _calculateNextBillingDate(
          nextBillingDate ?? DateTime.now().add(const Duration(days: 30)),
          billingCycle);

      return SubscriptionModel(
        id: DateTime.now().millisecondsSinceEpoch.toString(),
        serviceName: serviceName,
        monthlyCost: monthlyCost,
        billingCycle: billingCycle,
        nextBillingDate: adjustedNextBillingDate,
        isAutoDetected: true,
        repeatCount: actualRepeatCount,
        lastPaymentDate: lastPaymentDate,
        websiteUrl: _extractWebsiteUrl(serviceName),
        currency: currency, // 통화 단위 설정
      );
    } catch (e) {
      return null;
    }
  }

  // 다음 결제일 계산 (현재 날짜 기준으로 조정)
  DateTime _calculateNextBillingDate(
      DateTime billingDate, String billingCycle) {
    final now = DateTime.now();

    // 결제일이 이미 미래인 경우 그대로 반환
    if (billingDate.isAfter(now)) {
      return billingDate;
    }

    // 결제 주기별 다음 결제일 계산
    if (billingCycle == 'monthly') {
      int month = now.month;
      int year = now.year;

      // 현재 달의 결제일이 이미 지났으면 다음 달로 이동
      if (now.day >= billingDate.day) {
        month = month + 1;
        if (month > 12) {
          month = 1;
          year = year + 1;
        }
      }

      return DateTime(year, month, billingDate.day);
    } else if (billingCycle == 'yearly') {
      // 올해의 결제일이 지났는지 확인
      final thisYearBilling =
          DateTime(now.year, billingDate.month, billingDate.day);
      if (thisYearBilling.isBefore(now)) {
        return DateTime(now.year + 1, billingDate.month, billingDate.day);
      } else {
        return thisYearBilling;
      }
    } else if (billingCycle == 'weekly') {
      // 가장 가까운 다음 주 같은 요일 계산
      final dayDifference = billingDate.weekday - now.weekday;
      final daysToAdd = dayDifference > 0 ? dayDifference : 7 + dayDifference;
      return now.add(Duration(days: daysToAdd));
    }

    // 기본 처리: 30일 후
    return now.add(const Duration(days: 30));
  }

  String? _extractWebsiteUrl(String serviceName) {
    // SubscriptionUrlMatcher 서비스를 사용하여 URL 매칭 시도
    final suggestedUrl = SubscriptionUrlMatcher.findMatchingUrl(serviceName);

    // 매칭된 URL이 있으면 반환, 없으면 기존 매핑 사용
    if (suggestedUrl != null && suggestedUrl.isNotEmpty) {
      return suggestedUrl;
    }

    // 기존 하드코딩된 매핑 (필요한 경우 폴백으로 사용)
    final Map<String, String> serviceUrls = {
      '넷플릭스': 'https://www.netflix.com',
      '디즈니플러스': 'https://www.disneyplus.com',
      '유튜브프리미엄': 'https://www.youtube.com',
      'YouTube Premium': 'https://www.youtube.com',
      '애플 iCloud': 'https://www.icloud.com',
      'Microsoft 365': 'https://www.microsoft.com/microsoft-365',
      '멜론': 'https://www.melon.com',
      '웨이브': 'https://www.wavve.com',
      'Apple Music': 'https://www.apple.com/apple-music',
      'Netflix': 'https://www.netflix.com',
      'Disney+': 'https://www.disneyplus.com',
      'Spotify': 'https://www.spotify.com',
    };

    return serviceUrls[serviceName];
  }



  // 메시지에서 통화 단위를 감지하는 함수
  String _detectCurrency(String message) {
    final dollarKeywords = [
      '\$', 'USD', 'dollar', '달러', 'dollars', 'US\$',
      // 해외 서비스 이름
      'Netflix US', 'Spotify Premium', 'Apple US', 'Amazon US', 'GitHub'
    ];

    // 특정 서비스명으로 통화 단위 결정
    final Map<String, String> serviceCurrencyMap = {
      'Netflix US': 'USD',
      'Spotify Premium': 'USD',
      'Spotify': 'USD',
      'GitHub': 'USD',
      'GitHub Pro': 'USD',
    };

    // 서비스명 기반 통화 단위 확인
    for (final service in serviceCurrencyMap.keys) {
      if (message.contains(service)) {
        print('_detectCurrency: ${service}는 USD 서비스로 판별됨');
        return 'USD';
      }
    }

    // 메시지에 달러 관련 키워드가 있는지 확인
    for (final keyword in dollarKeywords) {
      if (message.toLowerCase().contains(keyword.toLowerCase())) {
        print('_detectCurrency: USD 키워드 발견: $keyword');
        return 'USD';
      }
    }

    // 기본값은 원화
    return 'KRW';
  }
}
