// ignore_for_file: unnecessary_library_name

@Skip('Requires live Naver API responses')
library naver_api_integration_test;

import 'package:flutter_test/flutter_test.dart';
import 'package:lunchpick/data/datasources/remote/naver_map_parser.dart';
import '../mocks/mock_naver_api_client.dart';

void main() {
  group('NaverMapParser - 네이버 API 통합 테스트', () {
    test('네이버 로컬 API 응답 시뮬레이션', () async {
      // 실제 네이버 로컬 API 응답 형식을 모방
      final mockApiClient = MockNaverApiClient();

      // HTML 응답 설정
      final htmlContent = '''
        <html>
          <head>
            <meta property="og:title" content="맛있는 김치찌개">
            <meta property="og:url" content="https://map.naver.com/p/restaurant/1234567890?y=37.5666805&x=126.9784147">
          </head>
          <body>
            <span class="GHAhO">맛있는 김치찌개</span>
            <span class="DJJvD">한식 > 김치찌개</span>
            <span class="IH7VW">서울특별시 종로구 세종대로 110</span>
            <span class="xlx7Q">02-1234-5678</span>
            <time class="aT6WB">매일 10:30 - 21:00</time>
            <div class="description">35년 전통의 김치찌개 전문점입니다.</div>
          </body>
        </html>
      ''';

      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/restaurant/1234567890',
        htmlContent,
      );

      // GraphQL 응답 설정
      mockApiClient.setGraphQLResponse({
        'place': {
          'id': '1234567890',
          'name': '맛있는 김치찌개',
          'category': '한식>김치찌개',
          'address': '서울특별시 종로구 세종대로 110',
          'roadAddress': '서울특별시 종로구 세종대로 110',
          'phone': '02-1234-5678',
          'businessHours': {'description': '매일 10:30 - 21:00'},
          'location': {'lat': 37.5666805, 'lng': 126.9784147},
        },
      });

      final parser = NaverMapParser(apiClient: mockApiClient);

      // 네이버 지도 URL로 파싱
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://map.naver.com/p/restaurant/1234567890',
      );

      // API 응답과 HTML 파싱 결과가 일치하는지 확인
      expect(restaurant.name, '맛있는 김치찌개');
      expect(restaurant.category, '한식');
      expect(restaurant.subCategory, '김치찌개');
      expect(restaurant.phoneNumber, '02-1234-5678');
      expect(restaurant.roadAddress, '서울특별시 종로구 세종대로 110');
      expect(restaurant.businessHours, '매일 10:30 - 21:00');

      // 좌표 변환이 올바른지 확인
      expect(restaurant.latitude, closeTo(37.5666805, 0.0000001));
      expect(restaurant.longitude, closeTo(126.9784147, 0.0000001));
    });

    test('좌표 변환 정확성 테스트', () async {
      final testCases = [
        {
          'mapx': '1269784147',
          'mapy': '375666805',
          'expectedLat': 37.5666805,
          'expectedLng': 126.9784147,
        },
        {
          'mapx': '1270333333',
          'mapy': '374999999',
          'expectedLat': 37.4999999,
          'expectedLng': 127.0333333,
        },
      ];

      for (final testCase in testCases) {
        final mockApiClient = MockNaverApiClient();

        final htmlContent =
            '''
          <html>
            <head>
              <meta property="og:url" content="https://map.naver.com/p/restaurant/1234567890?y=${testCase['expectedLat']}&x=${testCase['expectedLng']}">
            </head>
            <body>
              <span class="GHAhO">좌표 테스트 식당</span>
            </body>
          </html>
        ''';

        mockApiClient.setHtmlResponse(
          'https://map.naver.com/p/restaurant/1234567890',
          htmlContent,
        );

        // GraphQL 응답도 설정
        mockApiClient.setGraphQLResponse({
          'place': {
            'id': '1234567890',
            'name': '좌표 테스트 식당',
            'location': {
              'lat': testCase['expectedLat'],
              'lng': testCase['expectedLng'],
            },
          },
        });

        final parser = NaverMapParser(apiClient: mockApiClient);
        final restaurant = await parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/1234567890',
        );

        expect(
          restaurant.latitude,
          closeTo(testCase['expectedLat'] as double, 0.0000001),
          reason: '위도 변환이 정확해야 함',
        );
        expect(
          restaurant.longitude,
          closeTo(testCase['expectedLng'] as double, 0.0000001),
          reason: '경도 변환이 정확해야 함',
        );
      }
    });

    test('카테고리 정규화 테스트', () async {
      final categoryTests = [
        {'input': '한식>김치찌개', 'expectedMain': '한식', 'expectedSub': '김치찌개'},
        {'input': '카페,디저트', 'expectedMain': '카페', 'expectedSub': '카페'},
        {'input': '양식 > 파스타', 'expectedMain': '양식', 'expectedSub': '파스타'},
        {'input': '중식', 'expectedMain': '중식', 'expectedSub': '중식'},
      ];

      for (final test in categoryTests) {
        final mockApiClient = MockNaverApiClient();

        final htmlContent =
            '''
          <html>
            <body>
              <span class="GHAhO">카테고리 테스트</span>
              <span class="DJJvD">${test['input']}</span>
            </body>
          </html>
        ''';

        mockApiClient.setHtmlResponse(
          'https://map.naver.com/p/restaurant/1234567890',
          htmlContent,
        );

        final parser = NaverMapParser(apiClient: mockApiClient);
        final restaurant = await parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/1234567890',
        );

        expect(
          restaurant.category,
          test['expectedMain'],
          reason: '메인 카테고리가 올바르게 추출되어야 함: ${test['input']}',
        );
        expect(
          restaurant.subCategory,
          test['expectedSub'],
          reason: '서브 카테고리가 올바르게 추출되어야 함: ${test['input']}',
        );
      }
    });

    test('HTML 엔티티 디코딩 테스트', () async {
      final mockApiClient = MockNaverApiClient();

      final htmlContent = '''
        <html>
          <body>
            <span class="GHAhO">Tom &amp; Jerry&apos;s Restaurant</span>
            <span class="IH7VW">서울시 강남구 &lt;테헤란로&gt; 123번지</span>
            <span class="description">&quot;최고의 맛&quot;을 자랑하는 레스토랑</span>
          </body>
        </html>
      ''';

      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/restaurant/1234567890',
        htmlContent,
      );

      final parser = NaverMapParser(apiClient: mockApiClient);
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://map.naver.com/p/restaurant/1234567890',
      );

      expect(restaurant.name, contains('&'));
      expect(restaurant.name, contains("'"));
      expect(restaurant.roadAddress, contains('<'));
      expect(restaurant.roadAddress, contains('>'));
    });

    test('영업시간 파싱 다양성 테스트', () async {
      final businessHourTests = [
        '매일 11:00 - 22:00',
        '월-금 11:30 - 21:00, 주말 12:00 - 22:00',
        '연중무휴 24시간',
        '화요일 휴무, 그 외 10:00 - 20:00',
        '평일 11:00~14:00, 17:00~22:00 (브레이크타임 14:00~17:00)',
      ];

      for (final hours in businessHourTests) {
        final mockApiClient = MockNaverApiClient();

        final htmlContent =
            '''
          <html>
            <body>
              <span class="GHAhO">영업시간 테스트</span>
              <time class="aT6WB">$hours</time>
            </body>
          </html>
        ''';

        mockApiClient.setHtmlResponse(
          'https://map.naver.com/p/restaurant/1234567890',
          htmlContent,
        );

        final parser = NaverMapParser(apiClient: mockApiClient);
        final restaurant = await parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/1234567890',
        );

        expect(restaurant.businessHours, hours, reason: '영업시간이 정확히 파싱되어야 함');
      }
    });

    test('Place ID 추출 패턴 테스트', () async {
      final urlPatterns = [
        {
          'url': 'https://map.naver.com/p/restaurant/1234567890',
          'expectedId': '1234567890',
        },
        {
          'url': 'https://map.naver.com/p/entry/place/9876543210',
          'expectedId': '9876543210',
        },
        {
          'url': 'https://map.naver.com/p/restaurant/1234567890?entry=pll',
          'expectedId': '1234567890',
        },
      ];

      for (final pattern in urlPatterns) {
        final mockApiClient = MockNaverApiClient();

        final htmlContent = '''
          <html>
            <body>
              <span class="GHAhO">Place ID 테스트</span>
            </body>
          </html>
        ''';

        mockApiClient.setHtmlResponse(pattern['url']!, htmlContent);

        final parser = NaverMapParser(apiClient: mockApiClient);
        final restaurant = await parser.parseRestaurantFromUrl(pattern['url']!);

        expect(
          restaurant.naverPlaceId,
          pattern['expectedId'],
          reason: 'Place ID가 올바르게 추출되어야 함: ${pattern['url']}',
        );
      }
    });
  });

  group('NaverMapParser - 동시성 및 리소스 관리', () {
    test('동시 다중 요청 처리', () async {
      final mockApiClient = MockNaverApiClient();

      final parser = NaverMapParser(apiClient: mockApiClient);

      // 동시에 여러 요청 실행
      final futures = List.generate(5, (i) {
        final url = 'https://map.naver.com/p/restaurant/${1000 + i}';

        // 각 URL에 대한 HTML 응답 설정
        mockApiClient.setHtmlResponse(url, '''
            <html>
              <body>
                <span class="GHAhO">동시성 테스트 식당 ${i + 1}</span>
                <span class="DJJvD">한식</span>
              </body>
            </html>
          ''');

        return parser.parseRestaurantFromUrl(url);
      });

      final results = await Future.wait(futures);

      // 모든 요청이 성공했는지 확인
      expect(results.length, 5);

      // 각 결과가 고유한지 확인
      final names = results.map((r) => r.name).toSet();
      expect(names.length, 5);
    });

    test('리소스 정리 확인', () async {
      final mockApiClient = MockNaverApiClient();

      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/restaurant/123456789',
        '<html><body><span class="GHAhO">Test</span></body></html>',
      );

      final parser = NaverMapParser(apiClient: mockApiClient);

      // 여러 번 사용
      for (int i = 0; i < 3; i++) {
        try {
          await parser.parseRestaurantFromUrl(
            'https://map.naver.com/p/restaurant/123456789',
          );
        } catch (_) {
          // 에러 무시
        }
      }

      // dispose 호출
      parser.dispose();

      // dispose 후에는 사용할 수 없어야 함
      await expectLater(
        parser.parseRestaurantFromUrl('https://map.naver.com/p/restaurant/999'),
        throwsA(anything),
      );
    });
  });
}
