import 'dart:async';

import 'package:flutter/material.dart';

import 'package:collection/collection.dart';

import 'package:provider/provider.dart';

import 'package:pshared/models/payment/methods/data.dart';
import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/models/recipient/status.dart';
import 'package:pshared/models/recipient/type.dart';
import 'package:pshared/provider/organizations.dart';
import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pshared/provider/recipient/provider.dart';

import 'package:pweb/pages/address_book/form/view.dart';
import 'package:pweb/services/posthog.dart';
import 'package:pweb/utils/error/snackbar.dart';
import 'package:pweb/utils/payment/label.dart';
import 'package:pweb/utils/snackbar.dart';

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


class AddressBookRecipientForm extends StatefulWidget {
  final Recipient? recipient;
  final ValueChanged<Recipient?>? onSaved;

  const AddressBookRecipientForm({super.key, this.recipient, this.onSaved});

  @override
  State<AddressBookRecipientForm> createState() => _AddressBookRecipientFormState();
}

class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
  final _formKey = GlobalKey<FormState>();
  late TextEditingController _nameCtrl;
  late TextEditingController _emailCtrl;
  RecipientType _type = RecipientType.internal;
  RecipientStatus _status = RecipientStatus.ready;
  final MethodMap _methods = {};
  late PaymentMethodsProvider _methodsProvider;

  Future<void> _loadMethods() async {
    _methodsProvider = PaymentMethodsProvider()..addListener(_onProviderChanged);
    await _methodsProvider.loadMethods(
      context.read<OrganizationsProvider>(), 
      widget.recipient?.id,
    );

    for (final m in _methodsProvider.methods) {
      _methods[m.type] = switch (m.type) {
        PaymentType.card => m.cardData,
        PaymentType.iban => m.ibanData,
        PaymentType.wallet => m.walletData,
        PaymentType.bankAccount => m.bankAccountData,
        PaymentType.externalChain => m.cryptoAddressData,
        //TODO: support new payment methods
        _ => throw UnimplementedError('Payment method ${m.type} is not supported yet'),
      };
    }
  }

  @override
  void initState() {
    super.initState();
    final r = widget.recipient;
    _nameCtrl = TextEditingController(text: r?.name ?? '');
    _emailCtrl = TextEditingController(text: r?.email ?? '');
    _type = r?.type ?? RecipientType.internal;
    _status = r?.status ?? RecipientStatus.ready;
    _loadMethods();
  }

  Future<Recipient?> _doSave() async {
    final recipients = context.read<RecipientsProvider>();
    final methods = PaymentMethodsProvider();
    final recipient = widget.recipient == null
      ? await recipients.create(
          name: _nameCtrl.text,
          email: _emailCtrl.text,
        )
      : widget.recipient!;
    recipients.setCurrentObject(recipient.id);
    //TODO : redesign work with recipients / payment methods
    await methods.loadMethods(context.read<OrganizationsProvider>(), recipient.id);
    for (final type in _methods.keys) {
      final data = _methods[type]!;
      final exising = methods.methods.firstWhereOrNull((m) => m.type == type);
      if (exising != null) {
        await methods.updateMethod(exising.copyWith(data: data));
      } else {
        await methods.create(
          reacipientRef: recipient.id,
          name: getPaymentTypeLabel(context, type),
          data: data,
        );
      }
    }
    return recipient;
  }

  //TODO: Change when registration is ready
  Future<void> _save() async {
    final l10n = AppLocalizations.of(context)!;

    if (!_formKey.currentState!.validate()) {
      notifyUser(context, l10n.recipientFormValidationError);
      return;
    }

    if (_methods.isEmpty) {
      notifyUser(context, l10n.recipientFormRule);
      return;
    }

    unawaited(PosthogService.recipientAddCompleted(
      _type,
      _status,
      _methods.keys.toSet(),
    ));
    final recipient = await executeActionWithNotification(
      context: context, 
      action: _doSave, 
      errorMessage: l10n.errorSaveRecipient,
      successMessage: l10n.recipientSavedSuccessfully,
    );


    widget.onSaved?.call(recipient);
  }

  @override
  void dispose() {
    _methodsProvider.removeListener(_onProviderChanged);
    _methodsProvider.dispose();
    super.dispose();
  }

  void _onProviderChanged() => setState(() {});

  @override
  Widget build(BuildContext context) => FormView(
    formKey: _formKey,
    nameCtrl: _nameCtrl,
    emailCtrl: _emailCtrl,
    type: _type,
    status: _status,
    methods: _methods,
    onTypeChanged: (t) => setState(() => _type = t),
    onStatusChanged: (s) => setState(() => _status = s),
    onMethodsChanged: (type, data) {
      setState(() {
        if (data != null) {
          _methods[type] = data;
        } else {
          _methods.remove(type);
        }
      });
    },
    onSave: _save,
    isEditing: widget.recipient != null,
    onBack: () {
      widget.onSaved?.call(null);
    },
  );
}
