// lib/remote/remote_http.dart
import 'dart:convert';
import 'dart:developer' as dev;
import 'package:flutter/services.dart';

import 'remote_settings.dart';
import 'auth_client.dart';

/// Helper HTTP per risorse remote (URL + headers di autenticazione).
class RemoteHttp {
  static RemoteAuth? _auth;
  static String? _base;

  // Cache dell'ultimo set di header (mai null: {} se non autenticato)
  static Map<String, String> _cachedHeaders = const {};

  static Future<void>? _initFuture; // evita init concorrenti

  /// ✅ Inietta l'istanza di RemoteAuth usata dal controller,
  /// così API e immagini condividono lo stesso token/cache.
  static void attach({required String baseUrl, required RemoteAuth auth}) {
    _base = baseUrl.trim().isEmpty ? null : baseUrl.trim();
    _auth = auth;
    _cachedHeaders = const {};
    _initFuture = Future.value(); // init "risolta"
    dev.log('[RemoteHttp] attach: base=$_base (shared auth)', name: 'RemoteHttp');
  }

  /// Inizializza auth e base URL dai settings sicuri (robusto: non lancia).
  static Future<void> init() {
    _initFuture ??= _doInit();
    return _initFuture!;
  }

  static Future<void> _doInit() async {
    try {
      final s = await RemoteSettings.load();
      final base = s.baseUrl.trim();
      _base = base.isEmpty ? null : base;
      _auth = RemoteAuth(baseUrl: s.baseUrl, email: s.email, password: s.password);
      dev.log('[RemoteHttp] init: base=$_base, email=${s.email.isNotEmpty ? '***' : '(none)'}',
          name: 'RemoteHttp');
    } catch (e, st) {
      dev.log('[RemoteHttp] init ERROR: $e', name: 'RemoteHttp', error: e, stackTrace: st);
      _auth = null;
      _base = null;
    }
  }

  /// ✅ Se il token JWT è quasi scaduto, forziamo refresh prima di usarlo per le immagini.
  static bool _isJwtExpiringSoon(String token, {Duration skew = const Duration(seconds: 60)}) {
    try {
      final parts = token.split('.');
      if (parts.length < 2) return false;
      final payload = parts[1];

      String normalized = payload.replaceAll('-', '+').replaceAll('_', '/');
      while (normalized.length % 4 != 0) {
        normalized += '=';
      }

      final decoded = utf8.decode(base64.decode(normalized));
      final map = jsonDecode(decoded);
      if (map is! Map) return false;
      final exp = map['exp'];
      if (exp is! num) return false;

      final expMs = (exp.toInt()) * 1000;
      final nowMs = DateTime.now().millisecondsSinceEpoch;
      return (expMs - nowMs) <= skew.inMilliseconds;
    } catch (_) {
      return false;
    }
  }

  /// Headers correnti (login on‑demand). Non lancia; ritorna {} se non disponibili.
  static Future<Map<String, String>> headers() async {
    if (_auth == null) {
      await init();
      if (_auth == null) {
        _cachedHeaders = const {};
        dev.log('[RemoteHttp] headers: init failed → NO TOKEN', name: 'RemoteHttp');
        return _cachedHeaders;
      }
    }

    try {
      // ✅ refresh proattivo se token vicino a scadenza
      final tok = _auth!.token;
      if (tok != null && tok.isNotEmpty && _isJwtExpiringSoon(tok)) {
        dev.log('[RemoteHttp] token expiring soon -> refresh', name: 'RemoteHttp');
        final h = await _auth!.refreshAndHeaders();
        _cachedHeaders = Map<String, String>.from(h);
        return _cachedHeaders;
      }

      final h = await _auth!.authHeaders(); // login on-demand
      _cachedHeaders = Map<String, String>.from(h);

      if ((_cachedHeaders['Authorization']?.isEmpty ?? true)) {
        dev.log('[RemoteHttp] headers: NO Authorization', name: 'RemoteHttp');
      } else {
        dev.log('[RemoteHttp] headers: Authorization: Bearer ***', name: 'RemoteHttp');
      }
      return _cachedHeaders;
    } on PlatformException catch (e, st) {
      dev.log('[RemoteHttp] headers PlatformException: $e → returning {}',
          name: 'RemoteHttp', error: e, stackTrace: st);
      _cachedHeaders = const {};
      return _cachedHeaders;
    } catch (e, st) {
      dev.log('[RemoteHttp] headers ERROR: $e → returning {}',
          name: 'RemoteHttp', error: e, stackTrace: st);
      _cachedHeaders = const {};
      return _cachedHeaders;
    }
  }

  /// Ultimi header noti (sincrono). Mai null; {} se non autenticato.
  static Map<String, String> peekHeaders() => _cachedHeaders;

  /// Converte path relativo in assoluto. Se è già http/https lo ritorna com’è.
  static String absUrl(String? relativePath) {
    if (relativePath == null || relativePath.isEmpty) return '';
    final lp = relativePath.trim().toLowerCase();
    if (lp.startsWith('http://') || lp.startsWith('https://')) {
      return relativePath;
    }
    if (_base == null || _base!.isEmpty) return '';
    final b = _base!.endsWith('/') ? _base! : '${_base!}/';
    final rel = relativePath.startsWith('/') ? relativePath.substring(1) : relativePath;
    return '$b$rel';
  }

  /// Warm-up: scaldare gli header.
  static Future<void> warmUp() async {
    await init();
    try {
      await headers();
    } catch (_) {
      // già loggato
    }
  }

  /// Rilegge i settings a runtime (es. utente cambia base/email/password).
  static Future<void> refreshFromSettings() async {
    _initFuture = null;
    await init();
    _cachedHeaders = const {};
  }
}
