import 'dart:convert';

import 'package:dio/dio.dart';

import '../../../errors/ticker_content_unavailable_exception.dart';
import '../../errors/marianumconnect_error.dart';
import '../../marianumconnect_query.dart';
import 'get_ticker_page_response.dart';

/// Fetches a single ticker page from
/// `GET /api/mobile/v1/ticker/pages/{slug}`.
///
/// A CONTENT page whose ProseMirror JSON hasn't been backfilled yet answers
/// 404 `{ "error": "CONTENT_UNAVAILABLE", "webUrl": ... }`; that case is mapped
/// to a dedicated [TickerContentUnavailableException] carrying the browser
/// fallback URL, so the detail screen can offer "open in browser" instead of a
/// generic error. The bespoke 404 handling is why this keeps its own try/catch
/// instead of the base [guard].
class GetTickerPage extends MarianumConnectQuery {
  final String slug;

  GetTickerPage(this.slug, {super.dio});

  Future<TickerPageResponse> run() async {
    try {
      final response = await dio.get<Map<String, dynamic>>(
        endpoint('ticker/pages/${Uri.encodeComponent(slug)}'),
      );
      return TickerPageResponse.fromJson(response.data!);
    } on DioException catch (e) {
      throw _mapError(e);
    }
  }

  Object _mapError(DioException e) {
    final response = e.response;
    if (response?.statusCode == 404) {
      final body = _asMap(response?.data);
      if (body != null && body['error'] == 'CONTENT_UNAVAILABLE') {
        final webUrl = body['webUrl'];
        return TickerContentUnavailableException(
          webUrl: webUrl is String ? webUrl : null,
          technicalDetails: 'MC 404 CONTENT_UNAVAILABLE for slug=$slug',
        );
      }
    }
    return mapMarianumConnectError(e);
  }

  Map<String, dynamic>? _asMap(dynamic data) {
    if (data is Map<String, dynamic>) return data;
    if (data is String && data.isNotEmpty) {
      try {
        final decoded = jsonDecode(data);
        if (decoded is Map<String, dynamic>) return decoded;
      } catch (_) {
        return null;
      }
    }
    return null;
  }
}
