import 'package:flutter/material.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/screens/home/home_controller.dart' as hc;
import 'package:qpay/screens/pay/pay_controller.dart' as pc;

// Provide access to the shared types from one place.
typedef BillProvider = hc.BillProvider;
typedef BillProduct = pc.BillProduct;
typedef PaymentProcessor = pc.PaymentProcessor;

class ProviderScreenModel {
  List<BillProvider> providers = [];
  List<BillProduct> products = [];
  List<PaymentProcessor> processors = [];
  BillProvider? selectedProvider;
  BillProduct? selectedProduct;
  PaymentProcessor? selectedProcessor;
  bool isLoadingProviders = false;
  bool isLoadingProducts = false;
  bool isLoadingProcessors = false;
  String? errorMessage;
}

class ProviderController extends ChangeNotifier {
  final ProviderScreenModel model = ProviderScreenModel();
  final Http http = Http();
  BuildContext context;
  bool _disposed = false;

  ProviderController(this.context);

  @override
  void dispose() {
    _disposed = true;
    super.dispose();
  }

  dynamic _unwrap(dynamic response) {
    if (response is Map && response.containsKey('body')) {
      return response['body'];
    }
    return response;
  }

  // ── Providers ──────────────────────────────────────────────

  Future<ApiResponse<List<BillProvider>>> loadProviders(String currency) async {
    model.isLoadingProviders = true;
    model.errorMessage = null;
    model.providers = [];
    model.selectedProvider = null;
    model.products = [];
    model.selectedProduct = null;
    if (!_disposed) notifyListeners();

    try {
      final raw = await http.get(
        '/public/providers?currency=$currency&sort=priority,asc',
      );
      final response = _unwrap(raw);
      final List<dynamic> content;
      if (response is Map && response.containsKey('content')) {
        content = response['content'] as List<dynamic>;
      } else if (response is List) {
        content = response;
      } else {
        content = [];
      }
      model.providers = content
          .map((e) => BillProvider.fromJson(e as Map<String, dynamic>))
          .toList();
      model.isLoadingProviders = false;
      if (model.providers.isNotEmpty) {
        // Use selectProvider to also reset products and load matching products
        selectProvider(model.providers.first);
      } else {
        if (!_disposed) notifyListeners();
      }
      return ApiResponse.success(model.providers);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      model.providers = [];
      model.selectedProvider = null;
      model.isLoadingProviders = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure(
        "Problem fetching providers, are you connected to the internet?",
      );
    }
  }

  void selectProvider(BillProvider provider) {
    model.selectedProvider = provider;
    model.selectedProduct = null;
    model.products = [];
    if (!_disposed) notifyListeners();
    // Automatically load products for the selected provider
    loadProducts(provider.id);
  }

  // ── Products ───────────────────────────────────────────────

  Future<ApiResponse<List<BillProduct>>> loadProducts(String providerId) async {
    model.isLoadingProducts = true;
    model.errorMessage = null;
    model.selectedProduct = null;
    model.products = [];
    if (!_disposed) notifyListeners();

    try {
      final raw = await http.get('/public/providers/$providerId/products');
      final response = _unwrap(raw);
      final List<dynamic> list = response is List
          ? response
          : (response['content'] ?? []);
      model.products = list
          .map((e) => BillProduct.fromJson(e as Map<String, dynamic>))
          .toList();
      model.selectedProduct = model.products.isNotEmpty
          ? model.products.first
          : null;
      model.isLoadingProducts = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.success(model.products);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      model.products = [];
      model.selectedProduct = null;
      model.isLoadingProducts = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure(
        "Problem fetching products, are you connected to the internet?",
      );
    }
  }

  void selectProduct(BillProduct product) {
    model.selectedProduct = product;
    if (!_disposed) notifyListeners();
  }

  // ── Payment Processors ─────────────────────────────────────

  Future<ApiResponse<List<PaymentProcessor>>> loadProcessors(
    String currency,
  ) async {
    model.isLoadingProcessors = true;
    model.errorMessage = null;
    if (!_disposed) notifyListeners();

    try {
      final raw = await http.get(
        '/public/payment-processors?currency=$currency',
      );
      final response = _unwrap(raw);
      final List<dynamic> list = response is List
          ? response
          : (response['content'] ?? []);
      model.processors = list
          .map((e) => PaymentProcessor.fromJson(e as Map<String, dynamic>))
          .toList();
      if (model.processors.isNotEmpty && model.selectedProcessor == null) {
        model.selectedProcessor = model.processors.first;
      }
      model.isLoadingProcessors = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.success(model.processors);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      model.isLoadingProcessors = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure(
        "Problem fetching payment processors, are you connected to the internet?",
      );
    }
  }

  void selectProcessor(PaymentProcessor processor) {
    model.selectedProcessor = processor;
    if (!_disposed) notifyListeners();
  }
}
