import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:qpay/config/app_config.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/models/pageable_model.dart';

class HistoryModel {
  PageableModel? pageableModel;

  List<Map<String, dynamic>> transactions = [];
  bool isLoading = false;
  bool isLoadingMore = false;
  bool isActing = false;
  String? errorMessage;

  int currentPage = 0;
  int totalPages = 0;

  String searchQuery = '';
  String? statusFilter;
  String? typeFilter;

  bool selectMode = false;
  Set<String> selectedTransactionIds = {};
}

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

  HistoryController(this.context);

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

  void _safeNotify() {
    if (!_disposed) notifyListeners();
  }

  String buildQueryParameters(Map<String, String> params) {
    if (params.isEmpty) {
      return '';
    }

    String query = '';
    params.forEach((key, value) {
      query += '$key=$value&';
    });
    return query.substring(0, query.length - 1);
  }

  Future<ApiResponse<List<Map<String, dynamic>>>> getTransactions(
    Map<String, String> params,
  ) async {
    final isFirstPage = params['page'] == '0' || params['page'] == null;
    if (isFirstPage) {
      model.isLoading = true;
      model.transactions = [];
      model.currentPage = 0;
    } else {
      model.isLoadingMore = true;
    }
    _safeNotify();

    params['partyType'] = 'INDIVIDUAL,GROUP';

    try {
      Map<String, dynamic> response = await http.get(
        '/public/transaction?${buildQueryParameters(params)}',
      );

      model.pageableModel = PageableModel.fromJson(response);
      model.currentPage = model.pageableModel!.number;
      model.totalPages = model.pageableModel!.totalPages;

      final newItems = model.pageableModel!.content
          .map((e) => Map<String, dynamic>.from(e as Map))
          .toList();

      if (isFirstPage) {
        model.transactions = newItems;
      } else {
        model.transactions.addAll(newItems);
      }

      model.isLoading = false;
      model.isLoadingMore = false;
      _safeNotify();
      return ApiResponse.success(model.transactions);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      if (isFirstPage) {
        model.transactions = [];
      }
      model.isLoading = false;
      model.isLoadingMore = false;
      _safeNotify();
      return ApiResponse.failure(
        "Problem fetching transactions, are you connected to the internet?",
      );
    }
  }

  Future<void> searchTransactions(
    String workspaceId, {
    String? billName,
    String? status,
    String? type,
  }) async {
    model.searchQuery = billName ?? '';
    model.statusFilter = status;
    model.typeFilter = type;
    final params = <String, String>{
      'workspaceId': workspaceId,
      'page': '0',
      'size': '20',
      'sort': 'createdAt,desc',
    };
    if (billName != null && billName.isNotEmpty) {
      params['billName'] = billName;
    }
    if (status != null && status.isNotEmpty) {
      params['status'] = status;
    }
    if (type != null && type.isNotEmpty) {
      params['type'] = type;
    }
    await getTransactions(params);
  }

  Future<void> loadNextPage(String workspaceId) async {
    if (model.isLoadingMore || model.currentPage + 1 >= model.totalPages) {
      return;
    }
    final params = <String, String>{
      'workspaceId': workspaceId,
      'page': (model.currentPage + 1).toString(),
      'size': '20',
      'sort': 'createdAt,desc',
    };
    if (model.searchQuery.isNotEmpty) {
      params['billName'] = model.searchQuery;
    }
    if (model.statusFilter != null && model.statusFilter!.isNotEmpty) {
      params['status'] = model.statusFilter!;
    }
    if (model.typeFilter != null && model.typeFilter!.isNotEmpty) {
      params['type'] = model.typeFilter!;
    }
    await getTransactions(params);
  }

  void toggleSelectMode() {
    model.selectMode = !model.selectMode;
    if (!model.selectMode) {
      model.selectedTransactionIds.clear();
    }
    _safeNotify();
  }

  void toggleTransactionSelection(String id) {
    if (id.isEmpty) return;
    if (model.selectedTransactionIds.contains(id)) {
      model.selectedTransactionIds.remove(id);
    } else {
      model.selectedTransactionIds.add(id);
    }
    _safeNotify();
  }

  /// Removes selected transactions from the local list. The history
  /// endpoint does not support deletes, so this is a client-side action.
  void deleteSelectedTransactions() {
    final ids = List<String>.from(model.selectedTransactionIds);
    model.transactions.removeWhere((t) => ids.contains(t['id'] as String?));
    model.selectMode = false;
    model.selectedTransactionIds.clear();
    _safeNotify();
  }

  /// Builds the fully-qualified download URL for the transactions report.
  Uri _buildReportUrl({
    required String workspaceId,
    required DateTime startDate,
    required DateTime endDate,
  }) {
    final df = DateFormat("yyyy-MM-dd'T'HH:mm:ss");
    final start = Uri.encodeComponent(
      df.format(
        DateTime(startDate.year, startDate.month, startDate.day, 0, 0, 0),
      ),
    );
    final end = Uri.encodeComponent(
      df.format(
        DateTime(endDate.year, endDate.month, endDate.day, 23, 59, 59),
      ),
    );
    return Uri.parse(
      '${AppConfig.baseUrl}/public/reports/transactions/download'
      '?startDate=$start'
      '&endDate=$end'
      '&workspaceId=$workspaceId',
    );
  }

  /// Opens the transactions report download URL in the device browser.
  /// The browser handles the actual file download natively — no file I/O
  /// or plugin channels required, works on Android, iOS, and web.
  Future<void> downloadReport({
    required String workspaceId,
    required DateTime startDate,
    required DateTime endDate,
  }) async {
    model.isActing = true;
    _safeNotify();

    try {
      final uri = _buildReportUrl(
        workspaceId: workspaceId,
        startDate: startDate,
        endDate: endDate,
      );
      await launchUrl(uri, mode: LaunchMode.externalApplication);
    } catch (e) {
      logger.e('Failed to open report URL: $e');
      model.errorMessage = 'Failed to download report';
    } finally {
      model.isActing = false;
      _safeNotify();
    }
  }

  void clearFilters() {
    model.statusFilter = null;
    model.typeFilter = null;
    _safeNotify();
  }

  List<Map<String, dynamic>> getFakeTransactions() {
    return [
      {
        "id": "77b2c479-b803-49fc-b5c3-acbf52cba633",
        "trace": "22a3044b-8f53-4e43-b4f5-c77dcec48d2d",
        "amount": 25.0,
        "charge": 0.0,
        "gatewayCharge": 0.25,
        "tax": 0.5,
        "totalAmount": 25.75,
        "reference": "c838136c-c015-4a0b-9c7c-52f127c8c109",
        "paymentProcessorLabel": "MPGS",
        "paymentProcessorImage": "visa-mastercard.png",
        "debitPhone": "",
        "debitAccount": "",
        "debitCurrency": "USD",
        "debitRef": "Velocity",
        "creditPhone": "",
        "creditAccount": "07088597534",
        "billClientId": "powertel_zesa",
        "billName": "Zesa",
        "type": "REQUEST",
        "authType": "WEB",
        "errorMessage": "",
        "responseCode": "00",
        "status": "SUCCESS",
        "sdkActionId": "0aa0d90d-6132-48a7-a5d8-e796f757c73f",
      },
    ];
  }
}