// ignore_for_file: unnecessary_library_name

@Skip('Integration-heavy parser tests are temporarily disabled')
library naver_url_redirect_test;

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

void main() {
  group('NaverMapParser - 단축 URL 리다이렉션 종합 테스트', () {
    test('웹 환경에서 단축 URL 리다이렉션 성공', () async {
      final mockApiClient = MockNaverApiClient();

      // 단축 URL 리다이렉션 설정
      mockApiClient.setUrlRedirect(
        'https://naver.me/G7V4b1IN',
        'https://map.naver.com/p/restaurant/1234567890',
      );

      // HTML 응답 설정
      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/entry/place/1234567890',
        '''
        <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">서울시 종로구 세종로 1</span>
            <span class="xlx7Q">02-1234-5678</span>
            <time class="aT6WB">매일 11:00 - 22:00</time>
          </body>
        </html>
      ''',
      );

      final parser = NaverMapParser(apiClient: mockApiClient);
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://naver.me/G7V4b1IN',
      );

      expect(restaurant.name, '테스트 음식점');
      expect(restaurant.category, '한식');
      expect(restaurant.subCategory, '김치찌개');
      expect(restaurant.phoneNumber, '02-1234-5678');
      expect(restaurant.roadAddress, '서울시 종로구 세종로 1');
      expect(restaurant.latitude, 37.5666805);
      expect(restaurant.longitude, 126.9784147);
      expect(restaurant.businessHours, '매일 11:00 - 22:00');
      expect(restaurant.naverPlaceId, '1234567890');
    });

    test('리다이렉션 실패 시 폴백 처리', () async {
      final mockApiClient = MockNaverApiClient();

      // 리다이렉션 없음 (원본 URL 반환)
      mockApiClient.setUrlRedirect(
        'https://naver.me/abc123',
        'https://naver.me/abc123',
      );

      final parser = NaverMapParser(apiClient: mockApiClient);
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://naver.me/abc123',
      );

      // 리다이렉션 실패 시 단축 URL ID를 사용
      expect(restaurant.naverPlaceId, 'abc123');
      expect(restaurant.name, '네이버 지도 장소');
      expect(restaurant.category, '음식점');
      expect(restaurant.source, DataSource.NAVER);
    });

    test('다양한 리다이렉션 패턴 처리', () async {
      final mockApiClient = MockNaverApiClient();

      // 다른 형태의 URL로 리다이렉션
      mockApiClient.setUrlRedirect(
        'https://naver.me/xyz789',
        'https://map.naver.com/p/entry/place/9999999999',
      );

      // 최소한의 HTML
      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/entry/place/9999999999',
        '''
        <html>
          <head>
            <meta property="og:title" content="테스트 장소">
          </head>
          <body></body>
        </html>
      ''',
      );

      final parser = NaverMapParser(apiClient: mockApiClient);
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://naver.me/xyz789',
      );

      expect(restaurant.naverPlaceId, '9999999999');
      expect(restaurant.name, '테스트 장소');
    });
  });

  group('NaverMapParser - HTML 파싱 엣지 케이스', () {
    test('불완전한 HTML 구조 처리', () async {
      final mockApiClient = MockNaverApiClient();

      // 일부 정보만 있는 HTML
      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/entry/place/7777777777',
        '''
        <html>
          <body>
            <span class="GHAhO">부분 정보 식당</span>
            <!-- 카테고리 정보 없음 -->
            <!-- 주소 정보 없음 -->
            <span class="xlx7Q">02-9999-8888</span>
          </body>
        </html>
      ''',
      );

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

      expect(restaurant.name, '부분 정보 식당');
      expect(restaurant.category, '기타');
      expect(restaurant.phoneNumber, '02-9999-8888');
      expect(restaurant.roadAddress, '주소 정보 없음');
      expect(restaurant.latitude, 37.5666805); // 기본값
      expect(restaurant.longitude, 126.9784147); // 기본값
    });

    test('특수 문자가 포함된 데이터 처리', () async {
      final mockApiClient = MockNaverApiClient();

      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/entry/place/5555555555',
        '''
        <html>
          <head>
            <meta property="og:title" content="&lt;특수&gt; &amp; 문자 식당">
          </head>
          <body>
            <span class="GHAhO">&lt;특수&gt; &amp; 문자 식당</span>
            <span class="DJJvD">카페 &amp; 베이커리</span>
            <span class="IH7VW">서울시 강남구 테헤란로 123 &lt;1층&gt;</span>
          </body>
        </html>
      ''',
      );

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

      // HTML 엔티티가 제대로 디코딩되는지 확인
      expect(restaurant.name, contains('특수'));
      expect(restaurant.name, contains('문자 식당'));
      expect(restaurant.category, contains('카페'));
    });

    test('매우 긴 영업시간 정보 처리', () async {
      final mockApiClient = MockNaverApiClient();

      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/entry/place/3333333333',
        '''
        <html>
          <body>
            <span class="GHAhO">복잡한 영업시간 식당</span>
            <time class="aT6WB">월요일 11:00-15:00, 17:00-22:00 (브레이크타임 15:00-17:00), 화-금 11:00-22:00, 토요일 12:00-23:00, 일요일 휴무, 공휴일 12:00-21:00</time>
          </body>
        </html>
      ''',
      );

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

      expect(restaurant.businessHours, isNotNull);
      expect(restaurant.businessHours, contains('월요일'));
      expect(restaurant.businessHours, contains('브레이크타임'));
    });
  });

  group('NaverMapParser - 에러 처리 및 복구', () {
    test('네트워크 타임아웃 처리', () async {
      final mockApiClient = MockNaverApiClient();

      mockApiClient.shouldThrowError = true;
      mockApiClient.errorMessage = 'Request timeout';

      final parser = NaverMapParser(apiClient: mockApiClient);

      expect(
        () => parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/1234567890',
        ),
        throwsA(
          allOf(
            isA<NaverMapParseException>(),
            predicate<NaverMapParseException>(
              (e) => e.message.contains('네이버 지도 파싱 중 오류가 발생했습니다'),
            ),
          ),
        ),
      );
    });

    test('잘못된 JSON 응답 처리', () async {
      final mockApiClient = MockNaverApiClient();

      mockApiClient.shouldThrowError = true;
      mockApiClient.errorMessage = 'Invalid JSON';

      final parser = NaverMapParser(apiClient: mockApiClient);

      expect(
        () => parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/1234567890',
        ),
        throwsA(isA<NaverMapParseException>()),
      );
    });

    test('빈 응답 처리', () async {
      final mockApiClient = MockNaverApiClient();

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

      final parser = NaverMapParser(apiClient: mockApiClient);

      // 빈 응답이어도 기본값으로 처리되어야 함
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://map.naver.com/p/restaurant/1234567890',
      );
      expect(restaurant.name, '이름 없음');
      expect(restaurant.category, '기타');
    });

    test('404 응답 처리', () async {
      final mockApiClient = MockNaverApiClient();

      mockApiClient.shouldThrowError = true;
      mockApiClient.errorMessage = 'Not Found';

      final parser = NaverMapParser(apiClient: mockApiClient);

      expect(
        () => parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/nonexistent',
        ),
        throwsA(
          allOf(
            isA<NaverMapParseException>(),
            predicate<NaverMapParseException>(
              (e) => e.message.contains('네이버 지도 파싱 중 오류가 발생했습니다'),
            ),
          ),
        ),
      );
    });
  });

  group('NaverMapParser - 성능 및 메모리 테스트', () {
    test('대용량 HTML 파싱 성능', () async {
      final mockApiClient = MockNaverApiClient();

      // 큰 HTML 문서 생성
      final largeHtml =
          '''
        <html>
          <head>
            <meta property="og:title" content="성능 테스트 식당">
            <meta property="og:url" content="https://map.naver.com/p/restaurant/1234567890?y=37.5&x=127.0">
            ${List.generate(1000, (i) => '<meta name="dummy$i" content="dummy content $i">').join('\n')}
          </head>
          <body>
            <span class="GHAhO">성능 테스트 식당</span>
            ${List.generate(5000, (i) => '<div class="dummy">더미 콘텐츠 $i</div>').join('\n')}
            <span class="DJJvD">한식</span>
            <span class="IH7VW">서울시 종로구</span>
          </body>
        </html>
      ''';

      mockApiClient.setHtmlResponse(
        'https://map.naver.com/p/entry/place/1234567890',
        largeHtml,
      );

      final parser = NaverMapParser(apiClient: mockApiClient);

      // 성능 측정
      final stopwatch = Stopwatch()..start();
      final restaurant = await parser.parseRestaurantFromUrl(
        'https://map.naver.com/p/restaurant/1234567890',
      );
      stopwatch.stop();

      // 기본적인 파싱이 성공했는지 확인
      expect(restaurant.name, '성능 테스트 식당');
      expect(restaurant.category, '한식');

      // 파싱이 합리적인 시간 내에 완료되었는지 확인 (5초 이내)
      expect(stopwatch.elapsedMilliseconds, lessThan(5000));

      // 대용량 HTML 파싱 시간: ${stopwatch.elapsedMilliseconds}ms
    });

    test('여러 번의 연속 파싱', () async {
      final mockApiClient = MockNaverApiClient();

      final htmlContent = '''
        <html>
          <head>
            <meta property="og:title" content="연속 파싱 테스트">
          </head>
          <body>
            <span class="GHAhO">연속 파싱 테스트</span>
          </body>
        </html>
      ''';

      // 여러 URL에 대해 같은 HTML 설정
      for (int i = 0; i < 10; i++) {
        mockApiClient.setHtmlResponse(
          'https://map.naver.com/p/entry/place/${1000 + i}',
          htmlContent,
        );
      }

      final parser = NaverMapParser(apiClient: mockApiClient);

      // 여러 번 파싱 수행
      final futures = List.generate(
        10,
        (i) => parser.parseRestaurantFromUrl(
          'https://map.naver.com/p/restaurant/${1000 + i}',
        ),
      );

      final results = await Future.wait(futures);

      // 모든 파싱이 성공했는지 확인
      expect(results.length, 10);
      for (final restaurant in results) {
        expect(restaurant.name, '연속 파싱 테스트');
      }
    });
  });
}
