import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/screens/accounts/models/account_model.dart';
import 'package:qpay/screens/accounts/models/statement_model.dart';

class AccountProvider extends ChangeNotifier {
  final Http http = Http();

  AccountProvider();

  AccountModel? _account;
  StatementModel? _statement;
  bool _isLoadingAccount = false;
  bool _isLoadingStatement = false;
  String? _accountError;
  String? _statementError;

  /// Cached balances keyed by currency code (e.g. 'USD', 'ZWG').
  final Map<String, AccountModel?> _balances = {};

  AccountModel? get account => _account;
  StatementModel? get statement => _statement;
  bool get isLoadingAccount => _isLoadingAccount;
  bool get isLoadingStatement => _isLoadingStatement;
  String? get accountError => _accountError;
  String? get statementError => _statementError;
  bool _isDisposed = false;

  /// Returns a cached account balance for [currency], or null if not yet
  /// fetched.
  AccountModel? balanceForCurrency(String currency) {
    return _balances[currency.toUpperCase()];
  }

  /// Returns the account with name 'City Wallet' for [currency], or null.
  AccountModel? cityWalletBalance() {
    return _balances.values.firstWhere(
      (a) => a?.name == 'City Wallet',
      orElse: () => null,
    );
  }

  @override
  void notifyListeners() {
    if (!_isDisposed) {
      super.notifyListeners();
    }
  }

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

  Future<ApiResponse<AccountModel>> fetchAccount(
    String? workspaceId,
    String currency,
  ) async {
    _isLoadingAccount = true;
    _accountError = null;
    notifyListeners();

    try {
      Map<String, dynamic> response = await http.get(
        '/accounts/$workspaceId/balance/$currency',
      );

      _account = AccountModel.fromJson(response);
      _balances[currency.toUpperCase()] = _account;
      _isLoadingAccount = false;
      notifyListeners();
      return ApiResponse.success(_account!);
    } on DioException catch (e, s) {
      logger.e(s);
      _isLoadingAccount = false;
      _accountError = 'Failed to fetch account. Please try again.';
      notifyListeners();
      return ApiResponse.failure(_accountError!);
    } catch (e, s) {
      logger.e(e);
      logger.e(s);
      _isLoadingAccount = false;
      _accountError = 'An unexpected error occurred. Please try again.';
      notifyListeners();
      return ApiResponse.failure(_accountError!);
    }
  }

  /// Pre-load multiple currency balances at once. Results are stored in the
  /// [_balances] map so any widget can access them later.
  Future<void> preloadBalances(
    String? workspaceId,
    List<String> currencies,
  ) async {
    for (final currency in currencies) {
      await fetchAccount(workspaceId, currency);
    }
  }

  Future<ApiResponse<StatementModel>> fetchStatement({
    required String workspaceId,
    required String currency,
    required String startDate,
    required String endDate,
  }) async {
    _isLoadingStatement = true;
    _statementError = null;
    notifyListeners();

    try {
      Map<String, dynamic> response = await http.get(
        '/accounts/$workspaceId/statement/$currency'
        '?startDate=$startDate&endDate=$endDate',
      );

      _statement = StatementModel.fromJson(response);
      _isLoadingStatement = false;
      notifyListeners();
      return ApiResponse.success(_statement!);
    } on DioException catch (e, s) {
      logger.e(s);
      _isLoadingStatement = false;
      _statementError = 'Failed to fetch statement. Please try again.';
      notifyListeners();
      return ApiResponse.failure(_statementError!);
    } catch (e, s) {
      logger.e(s);
      _isLoadingStatement = false;
      _statementError = 'An unexpected error occurred. Please try again.';
      notifyListeners();
      return ApiResponse.failure(_statementError!);
    }
  }

  void clearAccount() {
    _account = null;
    _accountError = null;
    notifyListeners();
  }

  void clearStatement() {
    _statement = null;
    _statementError = null;
    notifyListeners();
  }
}