import 'package:html/dom.dart';
import 'package:lunchpick/core/utils/app_logger.dart';

/// 네이버 지도 HTML 파서
///
/// 네이버 지도 페이지의 HTML에서 식당 정보를 추출합니다.
class NaverHtmlParser {
  // CSS 셀렉터 상수
  static const List<String> _nameSelectors = [
    'span.GHAhO',
    'h1.Qpe7b',
    'span.Fc1rA',
    '[class*="place_name"]',
    'meta[property="og:title"]',
  ];

  static const List<String> _categorySelectors = [
    'span.DJJvD',
    'span.lnJFt',
    '[class*="category"]',
  ];

  static const List<String> _descriptionSelectors = [
    'span.IH7VW',
    'div.vV_z_',
    'meta[name="description"]',
  ];

  static const List<String> _phoneSelectors = [
    'span.xlx7Q',
    'a[href^="tel:"]',
    '[class*="phone"]',
  ];

  static const List<String> _addressSelectors = [
    'span.IH7VW',
    'span.jWDO_',
    '[class*="address"]',
  ];

  static const List<String> _businessHoursSelectors = [
    'time.aT6WB',
    'div.O8qbU',
    '[class*="business"]',
    '[class*="hours"]',
  ];

  /// HTML 문서에서 식당 정보 추출
  Map<String, dynamic> parseRestaurantInfo(Document document) {
    return {
      'name': extractName(document),
      'category': extractCategory(document),
      'subCategory': extractSubCategory(document),
      'description': extractDescription(document),
      'phone': extractPhoneNumber(document),
      'roadAddress': extractRoadAddress(document),
      'address': extractJibunAddress(document),
      'latitude': extractLatitude(document),
      'longitude': extractLongitude(document),
      'businessHours': extractBusinessHours(document),
    };
  }

  /// 식당 이름 추출
  String? extractName(Document document) {
    try {
      for (final selector in _nameSelectors) {
        final element = document.querySelector(selector);
        if (element != null) {
          if (element.localName == 'meta') {
            return element.attributes['content'];
          }
          final text = element.text.trim();
          if (text.isNotEmpty) {
            return text;
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 이름 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 카테고리 추출
  String? extractCategory(Document document) {
    try {
      for (final selector in _categorySelectors) {
        final element = document.querySelector(selector);
        if (element != null) {
          final text = element.text.trim();
          if (text.isNotEmpty) {
            // 첫 번째 카테고리만 추출 (예: "한식 > 국밥" -> "한식")
            return text.split('>').first.trim();
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 카테고리 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 서브 카테고리 추출
  String? extractSubCategory(Document document) {
    try {
      final element = document.querySelector('span.DJJvD, span.lnJFt');
      if (element != null) {
        final text = element.text.trim();
        if (text.contains('>')) {
          // 두 번째 카테고리 반환 (예: "한식 > 국밥" -> "국밥")
          return text.split('>').last.trim();
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 서브 카테고리 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 설명 추출
  String? extractDescription(Document document) {
    try {
      for (final selector in _descriptionSelectors) {
        final element = document.querySelector(selector);
        if (element != null) {
          if (element.localName == 'meta') {
            return element.attributes['content'];
          }
          final text = element.text.trim();
          if (text.isNotEmpty) {
            return text;
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 설명 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 전화번호 추출
  String? extractPhoneNumber(Document document) {
    try {
      for (final selector in _phoneSelectors) {
        final element = document.querySelector(selector);
        if (element != null) {
          if (element.localName == 'a' && element.attributes['href'] != null) {
            return element.attributes['href']!.replaceFirst('tel:', '');
          }
          final text = element.text.trim();
          if (text.isNotEmpty && RegExp(r'[\d\-\+\(\)]+').hasMatch(text)) {
            return text;
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 전화번호 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 도로명 주소 추출
  String? extractRoadAddress(Document document) {
    try {
      for (final selector in _addressSelectors) {
        final elements = document.querySelectorAll(selector);
        for (final element in elements) {
          final text = element.text.trim();
          // 도로명 주소 패턴 확인
          if (text.contains('로') || text.contains('길')) {
            return text;
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 도로명 주소 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 지번 주소 추출
  String? extractJibunAddress(Document document) {
    try {
      for (final selector in _addressSelectors) {
        final elements = document.querySelectorAll(selector);
        for (final element in elements) {
          final text = element.text.trim();
          // 지번 주소 패턴 확인 (숫자-숫자 형식 포함)
          if (RegExp(r'\d+\-\d+').hasMatch(text) &&
              !text.contains('로') &&
              !text.contains('길')) {
            return text;
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 지번 주소 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 위도 추출
  double? extractLatitude(Document document) {
    try {
      // 메타 태그에서 좌표 정보 찾기
      final metaElement = document.querySelector('meta[property="og:url"]');
      if (metaElement != null) {
        final content = metaElement.attributes['content'];
        if (content != null) {
          // URL에서 좌표 파라미터 추출 (예: ?y=37.5666805)
          final RegExp latRegex = RegExp(r'[?&]y=(\d+\.\d+)');
          final match = latRegex.firstMatch(content);
          if (match != null) {
            return double.tryParse(match.group(1)!);
          }
        }
      }

      // 자바스크립트 변수에서 추출 시도
      final scripts = document.querySelectorAll('script');
      for (final script in scripts) {
        final content = script.text;
        if (content.contains('latitude') || content.contains('lat')) {
          final RegExp latRegex = RegExp(r'(?:latitude|lat)["\s:]+(\d+\.\d+)');
          final match = latRegex.firstMatch(content);
          if (match != null) {
            return double.tryParse(match.group(1)!);
          }
        }
      }

      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 위도 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 경도 추출
  double? extractLongitude(Document document) {
    try {
      // 메타 태그에서 좌표 정보 찾기
      final metaElement = document.querySelector('meta[property="og:url"]');
      if (metaElement != null) {
        final content = metaElement.attributes['content'];
        if (content != null) {
          // URL에서 좌표 파라미터 추출 (예: ?x=126.9784147)
          final RegExp lonRegex = RegExp(r'[?&]x=(\d+\.\d+)');
          final match = lonRegex.firstMatch(content);
          if (match != null) {
            return double.tryParse(match.group(1)!);
          }
        }
      }

      // 자바스크립트 변수에서 추출 시도
      final scripts = document.querySelectorAll('script');
      for (final script in scripts) {
        final content = script.text;
        if (content.contains('longitude') || content.contains('lng')) {
          final RegExp lonRegex = RegExp(r'(?:longitude|lng)["\s:]+(\d+\.\d+)');
          final match = lonRegex.firstMatch(content);
          if (match != null) {
            return double.tryParse(match.group(1)!);
          }
        }
      }

      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 경도 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  /// 영업시간 추출
  String? extractBusinessHours(Document document) {
    try {
      for (final selector in _businessHoursSelectors) {
        final elements = document.querySelectorAll(selector);
        for (final element in elements) {
          final text = element.text.trim();
          if (text.isNotEmpty &&
              (text.contains('시') ||
                  text.contains(':') ||
                  text.contains('영업'))) {
            return text;
          }
        }
      }
      return null;
    } catch (e, stackTrace) {
      AppLogger.error(
        'NaverHtmlParser: 영업시간 추출 실패 - $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }
}
