import 'package:flutter/material.dart';

import 'package:flutter_multi_formatter/flutter_multi_formatter.dart';

import 'package:pshared/models/payment/methods/card.dart';

import 'package:pweb/utils/text_field_styles.dart';

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


class CardFormMinimal extends StatefulWidget {
  final void Function(CardPaymentMethod) onChanged;
  final CardPaymentMethod? initialData;
  final bool isEditable;

  const CardFormMinimal({
    super.key,
    required this.onChanged,
    this.initialData,
    required this.isEditable,
  });

  @override
  State<CardFormMinimal> createState() => _CardFormMinimalState();
}

class _CardFormMinimalState extends State<CardFormMinimal> {
  final _formKey = GlobalKey<FormState>();
  late TextEditingController _panController;
  late TextEditingController _firstNameController;
  late TextEditingController _lastNameController;
  late TextEditingController _expiryController;

  @override
  void initState() {
    super.initState();
    _panController = TextEditingController(text: widget.initialData?.pan ?? '');
    _firstNameController = TextEditingController(text: widget.initialData?.firstName ?? '');
    _lastNameController = TextEditingController(text: widget.initialData?.lastName ?? '');
    _expiryController = TextEditingController(text: _formatExpiry(widget.initialData));

    WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
  }

  void _emitIfValid() {
    if (_formKey.currentState?.validate() ?? false) {
      final expiry = _parseExpiry(_expiryController.text);
      if (expiry == null) return;

      widget.onChanged(
        CardPaymentMethod(
          pan: _panController.text.replaceAll(' ', ''),
          firstName: _firstNameController.text,
          lastName: _lastNameController.text,
          expMonth: expiry.month,
          expYear: expiry.year,
        ),
      );
    }
  }

  @override
  void didUpdateWidget(covariant CardFormMinimal oldWidget) {
    super.didUpdateWidget(oldWidget);
    final newData = widget.initialData;
    final oldData = oldWidget.initialData;

    if (newData == null && oldData != null) {
      _panController.clear();
      _firstNameController.clear();
      _lastNameController.clear();
      _expiryController.clear();
      return;
    }

    if (newData != null && newData != oldData) {
      final hasPanChange = newData.pan != _panController.text;
      final hasFirstNameChange = newData.firstName != _firstNameController.text;
      final hasLastNameChange = newData.lastName != _lastNameController.text;
      final hasExpiryChange = _formatExpiry(newData) != _expiryController.text;

      if (hasPanChange) _panController.text = newData.pan;
      if (hasFirstNameChange) _firstNameController.text = newData.firstName;
      if (hasLastNameChange) _lastNameController.text = newData.lastName;
      if (hasExpiryChange) _expiryController.text = _formatExpiry(newData);

      if (hasPanChange || hasFirstNameChange || hasLastNameChange || hasExpiryChange) {
        WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;
    return Form(
      key: _formKey,
      onChanged: _emitIfValid,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextFormField(
            readOnly: !widget.isEditable,
            controller: _panController,
            decoration: getInputDecoration(context, l10n.cardNumber, widget.isEditable),
            style: getTextFieldStyle(context, widget.isEditable),
            keyboardType: TextInputType.number,
            inputFormatters: [CreditCardNumberInputFormatter()],
            validator: (v) => (v == null || v.replaceAll(' ', '').length < 12) ? l10n.enterCardNumber : null,
          ),
          const SizedBox(height: 12),
          TextFormField(
            readOnly: !widget.isEditable,
            controller: _firstNameController,
            decoration: getInputDecoration(context, l10n.firstName, widget.isEditable),
            style: getTextFieldStyle(context, widget.isEditable),
            validator: (v) => (v == null || v.isEmpty) ? l10n.enterFirstName : null,
          ),
          const SizedBox(height: 12),
          TextFormField(
            readOnly: !widget.isEditable,
            controller: _lastNameController,
            decoration: getInputDecoration(context, l10n.lastName, widget.isEditable),
            style: getTextFieldStyle(context, widget.isEditable),
            validator: (v) => (v == null || v.isEmpty) ? l10n.enterLastName : null,
          ),
          const SizedBox(height: 12),
          TextFormField(
            readOnly: !widget.isEditable,
            controller: _expiryController,
            decoration: getInputDecoration(context, l10n.expiryDate, widget.isEditable),
            style: getTextFieldStyle(context, widget.isEditable),
            keyboardType: TextInputType.number,
            inputFormatters: [CreditCardExpirationDateFormatter()],
            validator: (v) => _parseExpiry(v ?? '') == null ? l10n.enterExpiryDate : null,
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _panController.dispose();
    _firstNameController.dispose();
    _lastNameController.dispose();
    _expiryController.dispose();
    super.dispose();
  }

  String _formatExpiry(CardPaymentMethod? data) {
    if (data == null) return '';
    if (data.expMonth == null || data.expYear == null) return '';
    final month = data.expMonth!.toString().padLeft(2, '0');
    final year = (data.expYear! % 100).toString().padLeft(2, '0');
    return '$month/$year';
  }

  _CardExpiry? _parseExpiry(String value) {
    final normalized = value.trim();
    final match = RegExp(r'^(\d{2})\s*/\s*(\d{2})$').firstMatch(normalized);
    if (match == null) return null;

    final month = int.tryParse(match.group(1)!);
    final year = int.tryParse(match.group(2)!);
    if (month == null || year == null || month < 1 || month > 12) return null;

    final normalizedYear = 2000 + year;
    return _CardExpiry(month: month, year: normalizedYear);
  }
}

class _CardExpiry {
  final int month;
  final int year;

  const _CardExpiry({required this.month, required this.year});
}
