import 'package:flutter/material.dart';

import 'package:provider/provider.dart';

import 'package:pshared/models/payment/operation.dart';
import 'package:pshared/models/payment/payment.dart';
import 'package:pshared/models/payment/status.dart';
import 'package:pshared/provider/payment/payments.dart';

import 'package:pweb/pages/report/charts/distribution.dart';
import 'package:pweb/pages/report/charts/status.dart';
import 'package:pweb/pages/report/table/filters.dart';
import 'package:pweb/pages/report/table/widget.dart';

import 'package:pweb/generated/i18n/app_localizations.dart';


class OperationHistoryPage extends StatefulWidget {
  const OperationHistoryPage({super.key});

  @override
  State<OperationHistoryPage> createState() => _OperationHistoryPageState();
}

class _OperationHistoryPageState extends State<OperationHistoryPage> {
  DateTimeRange? _pendingRange;
  DateTimeRange? _appliedRange;
  final Set<OperationStatus> _pendingStatuses = {};
  Set<OperationStatus> _appliedStatuses = {};

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final provider = context.read<PaymentsProvider>();
      if (!provider.isReady && !provider.isLoading) {
        provider.refresh();
      }
    });
  }

  Future<void> _pickRange() async {
    final now = DateTime.now();
    final initial = _pendingRange ??
        DateTimeRange(
          start: now.subtract(const Duration(days: 30)),
          end: now,
        );
    
    final picked = await showDateRangePicker(
      context: context,
      firstDate: DateTime(2000),
      lastDate: now.add(const Duration(days: 1)),
      initialDateRange: initial,
    );
    
    if (picked != null) {
      setState(() {
        _pendingRange = picked;
      });
    }
  }

  void _toggleStatus(OperationStatus status) {
    setState(() {
      if (_pendingStatuses.contains(status)) {
        _pendingStatuses.remove(status);
      } else {
        _pendingStatuses.add(status);
      }
    });
  }

  void _applyFilters() {
    setState(() {
      _appliedRange = _pendingRange;
      _appliedStatuses = {..._pendingStatuses};
    });
  }

  List<OperationItem> _mapPayments(List<Payment> payments) {
    return payments.map(_mapPayment).toList();
  }

  OperationItem _mapPayment(Payment payment) {
    final debit = payment.lastQuote?.debitAmount;
    final settlement = payment.lastQuote?.expectedSettlementAmount;
    final amountMoney = debit ?? settlement;

    final amount = _parseAmount(amountMoney?.amount);
    final currency = amountMoney?.currency ?? '';
    final toAmount = settlement == null ? amount : _parseAmount(settlement.amount);
    final toCurrency = settlement?.currency ?? currency;

    final payId = _firstNonEmpty([payment.paymentRef, payment.idempotencyKey]) ?? '-';
    final name = _firstNonEmpty([payment.lastQuote?.quoteRef, payment.paymentRef, payment.idempotencyKey]) ?? '-';
    final comment = _firstNonEmpty([payment.failureReason, payment.failureCode, payment.state]) ?? '';

    return OperationItem(
      status: _statusFromPaymentState(payment.state),
      fileName: null,
      amount: amount,
      currency: currency,
      toAmount: toAmount,
      toCurrency: toCurrency,
      payId: payId,
      paymentRef: payment.paymentRef,
      cardNumber: null,
      name: name,
      date: _resolvePaymentDate(payment),
      comment: comment,
    );
  }

  List<OperationItem> _filterOperations(List<OperationItem> operations) {
    if (_appliedRange == null && _appliedStatuses.isEmpty) {
      return operations;
    }

    return operations.where((op) {
      final statusMatch =
          _appliedStatuses.isEmpty || _appliedStatuses.contains(op.status);

      final dateMatch = _appliedRange == null ||
          _isUnknownDate(op.date) ||
          (op.date.isAfter(_appliedRange!.start.subtract(const Duration(seconds: 1))) &&
              op.date.isBefore(_appliedRange!.end.add(const Duration(seconds: 1))));

      return statusMatch && dateMatch;
    }).toList();
  }

  OperationStatus _statusFromPaymentState(String? raw) {
    final state = raw?.trim().toLowerCase();

    switch (state) {
      case 'accepted':
      case 'funds_reserved':
      case 'submitted':
      case 'unspecified':
      case null:
        return OperationStatus.processing;

      case 'settled':
      case 'success':
        return OperationStatus.success;

      case 'failed':
      case 'cancelled':
        return OperationStatus.error;

      default:
        // Future-proof: any new backend state is treated as processing
        return OperationStatus.processing;
    }
  }

  DateTime _resolvePaymentDate(Payment payment) {
    final expiresAt = payment.lastQuote?.fxQuote?.expiresAtUnixMs;
    if (expiresAt != null && expiresAt > 0) {
      return DateTime.fromMillisecondsSinceEpoch(expiresAt, isUtc: true);
    }
    return DateTime.fromMillisecondsSinceEpoch(0, isUtc: true);
  }

  double _parseAmount(String? amount) {
    if (amount == null || amount.trim().isEmpty) return 0;
    return double.tryParse(amount) ?? 0;
  }

  String? _firstNonEmpty(List<String?> values) {
    for (final value in values) {
      final trimmed = value?.trim();
      if (trimmed != null && trimmed.isNotEmpty) return trimmed;
    }
    return null;
  }

  bool _isUnknownDate(DateTime date) => date.millisecondsSinceEpoch == 0;

  @override
  Widget build(BuildContext context) {
    final loc = AppLocalizations.of(context)!;
    return Consumer<PaymentsProvider>(
      builder: (context, provider, child) {
        if (provider.isLoading) {
          return const Center(child: CircularProgressIndicator());
        }
        
        if (provider.error != null) {
          final message = provider.error?.toString() ?? loc.noErrorInformation;
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(loc.notificationError(message)),
                ElevatedButton(
                  onPressed: () => provider.refresh(),
                  child: Text(loc.retry),
                ),
              ],
            ),
          );
        }

        final operations = _mapPayments(provider.payments);
        final filteredOperations = _filterOperations(operations);
        final hasFileName = operations.any(
          (operation) => (operation.fileName ?? '').trim().isNotEmpty,
        );
        
        return Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            spacing: 16,
            children: [
              SizedBox(
                height: 200,
                child: Row(
                  spacing: 16,
                  children: [
                    Expanded(
                      child: StatusChart(operations: operations),
                    ),
                    Expanded(
                      child: PayoutDistributionChart(
                        operations: operations,
                      ),
                    ),
                  ],
                ),
              ),
              OperationFilters(
                selectedRange: _pendingRange,
                selectedStatuses: _pendingStatuses,
                onPickRange: _pickRange,
                onToggleStatus: _toggleStatus,
                onApply: _applyFilters,
              ),
              OperationsTable(
                operations: filteredOperations,
                showFileNameColumn: hasFileName,
              ),
            ],
          ),
        );
      },
    );
  }
}
