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

import '../../../core/constants/api_keys.dart';
import '../../../core/network/network_client.dart';
import '../../../core/errors/network_exceptions.dart';

/// 네이버 로컬 검색 API 결과 모델
class NaverLocalSearchResult {
  final String title;
  final String link;
  final String category;
  final String description;
  final String telephone;
  final String address;
  final String roadAddress;
  final double? mapx;
  final double? mapy;

  NaverLocalSearchResult({
    required this.title,
    required this.link,
    required this.category,
    required this.description,
    required this.telephone,
    required this.address,
    required this.roadAddress,
    this.mapx,
    this.mapy,
  });

  factory NaverLocalSearchResult.fromJson(Map<String, dynamic> json) {
    // HTML 태그 제거 헬퍼 함수
    String removeHtmlTags(String text) {
      return text
          .replaceAll(RegExp(r'<[^>]*>'), '')
          .replaceAll('&amp;', '&')
          .replaceAll('&lt;', '<')
          .replaceAll('&gt;', '>')
          .replaceAll('&quot;', '"')
          .replaceAll('&#39;', "'")
          .replaceAll('&nbsp;', ' ');
    }

    return NaverLocalSearchResult(
      title: removeHtmlTags(json['title'] ?? ''),
      link: json['link'] ?? '',
      category: json['category'] ?? '',
      description: removeHtmlTags(json['description'] ?? ''),
      telephone: json['telephone'] ?? '',
      address: json['address'] ?? '',
      roadAddress: json['roadAddress'] ?? '',
      mapx: json['mapx'] != null
          ? double.tryParse(json['mapx'].toString())
          : null,
      mapy: json['mapy'] != null
          ? double.tryParse(json['mapy'].toString())
          : null,
    );
  }

  /// link 필드에서 Place ID 추출
  ///
  /// link가 비어있거나 Place ID가 없으면 null 반환
  String? extractPlaceId() {
    if (link.isEmpty) return null;

    // 네이버 지도 URL 패턴에서 Place ID 추출
    // 예: https://map.naver.com/p/entry/place/1638379069
    final placeIdMatch = RegExp(r'/place/(\d+)').firstMatch(link);
    if (placeIdMatch != null) {
      return placeIdMatch.group(1);
    }

    // 다른 패턴 시도: restaurant/1638379069
    final restaurantIdMatch = RegExp(r'/restaurant/(\d+)').firstMatch(link);
    if (restaurantIdMatch != null) {
      return restaurantIdMatch.group(1);
    }

    // ID만 있는 경우 (10자리 숫자)
    final idOnlyMatch = RegExp(r'(\d{10})').firstMatch(link);
    if (idOnlyMatch != null) {
      return idOnlyMatch.group(1);
    }

    return null;
  }
}

/// 네이버 로컬 검색 API 클라이언트
///
/// 네이버 검색 API를 통해 장소 정보를 검색합니다.
class NaverLocalSearchApi {
  final NetworkClient _networkClient;

  NaverLocalSearchApi({NetworkClient? networkClient})
    : _networkClient = networkClient ?? NetworkClient();

  /// 로컬 검색 API 호출
  ///
  /// 검색어와 좌표를 기반으로 주변 식당을 검색합니다.
  Future<List<NaverLocalSearchResult>> searchLocal({
    required String query,
    double? latitude,
    double? longitude,
    int display = 20,
    int start = 1,
    String sort = 'random', // random, comment
  }) async {
    // API 키 확인
    if (!ApiKeys.areKeysConfigured()) {
      throw ApiKeyException();
    }

    try {
      final response = await _networkClient.get<Map<String, dynamic>>(
        ApiKeys.naverLocalSearchEndpoint,
        queryParameters: {
          'query': query,
          'display': display,
          'start': start,
          'sort': sort,
          if (latitude != null && longitude != null) ...{
            'coordinate': '$longitude,$latitude', // 경도,위도 순서
          },
        },
        options: Options(
          headers: {
            'X-Naver-Client-Id': ApiKeys.naverClientId,
            'X-Naver-Client-Secret': ApiKeys.naverClientSecret,
          },
        ),
      );

      final data = response.data;
      if (data == null || data['items'] == null) {
        return [];
      }

      final items = data['items'] as List;
      return items
          .map((item) => NaverLocalSearchResult.fromJson(item))
          .toList();
    } on DioException catch (e) {
      AppLogger.error(
        'NaverLocalSearchApi error: ${e.message}',
        error: e,
        stackTrace: e.stackTrace,
      );
      AppLogger.debug('Error type: ${e.type}');
      AppLogger.debug('Error response: ${e.response?.data}');

      if (e.error is NetworkException) {
        throw e.error!;
      }
      throw ServerException(
        message: '네이버 검색 중 오류가 발생했습니다',
        statusCode: e.response?.statusCode ?? 500,
        originalError: e,
      );
    }
  }

  /// 특정 식당 상세 정보 검색
  Future<NaverLocalSearchResult?> searchRestaurantDetails({
    required String name,
    required String address,
    double? latitude,
    double? longitude,
  }) async {
    try {
      // 주소와 이름을 조합한 검색어
      final query = '$name $address';
      final results = await searchLocal(
        query: query,
        latitude: latitude,
        longitude: longitude,
        display: 5,
        sort: 'comment', // 정확도순
      );

      if (results.isEmpty) {
        return null;
      }

      // 가장 정확한 결과 찾기
      for (final result in results) {
        if (result.title.contains(name) || name.contains(result.title)) {
          return result;
        }
      }

      // 정확한 매칭이 없으면 첫 번째 결과 반환
      return results.first;
    } catch (e, stackTrace) {
      AppLogger.error(
        'searchRestaurantDetails error: $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    }
  }

  void dispose() {
    // 필요시 리소스 정리
  }
}
