import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:lunchpick/core/utils/app_logger.dart';

import '../../../core/network/network_client.dart';
import '../../../core/network/network_config.dart';

/// 네이버 URL 리졸버
///
/// 네이버 단축 URL을 실제 URL로 변환하고 최종 리다이렉트 URL을 추적합니다.
class NaverUrlResolver {
  final NetworkClient _networkClient;

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

  /// 단축 URL을 실제 URL로 변환
  Future<String> resolveShortUrl(String shortUrl) async {
    try {
      // 웹 환경에서는 CORS 프록시 사용
      if (kIsWeb) {
        return await _resolveShortUrlViaProxy(shortUrl);
      }

      // 모바일 환경에서는 직접 HEAD 요청
      final response = await _networkClient.head(
        shortUrl,
        options: Options(
          followRedirects: false,
          validateStatus: (status) => status! < 400,
        ),
      );

      // Location 헤더에서 리다이렉트 URL 추출
      final location = response.headers.value('location');
      if (location != null) {
        return location;
      }

      // Location이 없는 경우, http.Client로 리다이렉트를 끝까지 따라가며 최종 URL 추출 (fallback)
      final expanded = await _followRedirectsWithHttp(shortUrl);
      if (expanded != null) {
        return expanded;
      }

      // 리다이렉트가 없으면 원본 URL 반환
      return shortUrl;
    } on DioException catch (e) {
      AppLogger.error(
        'resolveShortUrl error: $e',
        error: e,
        stackTrace: e.stackTrace,
      );

      // 리다이렉트 응답인 경우 Location 헤더 확인
      if (e.response?.statusCode == 301 || e.response?.statusCode == 302) {
        final location = e.response?.headers.value('location');
        if (location != null) {
          return location;
        }
      }

      // Dio 실패 시 fallback으로 http.Client 리다이렉트 추적 시도
      final expanded = await _followRedirectsWithHttp(shortUrl);
      if (expanded != null) {
        return expanded;
      }

      // 오류 발생 시 원본 URL 반환
      return shortUrl;
    }
  }

  /// 프록시를 통한 단축 URL 해결 (웹 환경)
  Future<String> _resolveShortUrlViaProxy(String shortUrl) async {
    try {
      final proxyUrl = NetworkConfig.getCorsProxyUrl(shortUrl);

      final response = await _networkClient.get(
        proxyUrl,
        options: Options(
          followRedirects: false,
          validateStatus: (status) => true,
          responseType: ResponseType.plain,
        ),
      );

      // 응답에서 URL 정보 추출
      final responseData = response.data.toString();

      // meta refresh 태그에서 URL 추출
      final metaRefreshRegex = RegExp(
        '<meta[^>]+http-equiv="refresh"[^>]+content="0;url=([^"]+)"[^>]*>',
        caseSensitive: false,
      );
      final metaMatch = metaRefreshRegex.firstMatch(responseData);
      if (metaMatch != null) {
        return metaMatch.group(1) ?? shortUrl;
      }

      // og:url 메타 태그에서 URL 추출
      final ogUrlRegex = RegExp(
        '<meta[^>]+property="og:url"[^>]+content="([^"]+)"[^>]*>',
        caseSensitive: false,
      );
      final ogMatch = ogUrlRegex.firstMatch(responseData);
      if (ogMatch != null) {
        return ogMatch.group(1) ?? shortUrl;
      }

      // Location 헤더 확인
      final location = response.headers.value('location');
      if (location != null) {
        return location;
      }

      return shortUrl;
    } catch (e, stackTrace) {
      AppLogger.error(
        '_resolveShortUrlViaProxy error: $e',
        error: e,
        stackTrace: stackTrace,
      );
      return shortUrl;
    }
  }

  /// 최종 리다이렉트 URL 가져오기
  ///
  /// 여러 단계의 리다이렉트를 거쳐 최종 URL을 반환합니다.
  Future<String> getFinalRedirectUrl(String url) async {
    try {
      String currentUrl = url;
      int redirectCount = 0;
      const maxRedirects = 5;

      while (redirectCount < maxRedirects) {
        final response = await _networkClient.head(
          currentUrl,
          options: Options(
            followRedirects: false,
            validateStatus: (status) => status! < 400,
          ),
        );

        final location = response.headers.value('location');
        if (location == null) {
          break;
        }

        // 절대 URL로 변환
        if (location.startsWith('/')) {
          final uri = Uri.parse(currentUrl);
          currentUrl = '${uri.scheme}://${uri.host}$location';
        } else {
          currentUrl = location;
        }

        redirectCount++;
      }

      return currentUrl;
    } catch (e, stackTrace) {
      AppLogger.error(
        'getFinalRedirectUrl error: $e',
        error: e,
        stackTrace: stackTrace,
      );
      return url;
    }
  }

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

  /// http.Client를 사용해 리다이렉트를 끝까지 따라가며 최종 URL을 반환한다.
  /// 실패 시 null 반환.
  Future<String?> _followRedirectsWithHttp(String shortUrl) async {
    final client = http.Client();
    try {
      final request = http.Request('HEAD', Uri.parse(shortUrl))
        ..followRedirects = true
        ..maxRedirects = 5;
      final response = await client.send(request);
      return response.request?.url.toString();
    } catch (e, stackTrace) {
      AppLogger.error(
        '_followRedirectsWithHttp error: $e',
        error: e,
        stackTrace: stackTrace,
      );
      return null;
    } finally {
      client.close();
    }
  }
}
