import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/collections/account.dart';
import 'package:okane/database/collections/beneficiary.dart';
import 'package:okane/database/collections/expense_category.dart';
import 'package:okane/database/collections/template.dart';
import 'package:okane/database/collections/transaction.dart';
import 'package:okane/database/database.dart';
import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/transaction.dart';
import 'package:okane/ui/utils.dart';
import 'package:okane/ui/widgets/add_expense_category.dart';
import 'package:searchfield/searchfield.dart';

typedef AddTransactionCallback = void Function(Transaction);

class AddTransactionWidget extends StatefulWidget {
  final AddTransactionCallback onAdd;

  final Account activeAccountItem;

  final TransactionTemplate? template;

  const AddTransactionWidget({
    super.key,
    this.template,
    required this.activeAccountItem,
    required this.onAdd,
  });

  @override
  State<AddTransactionWidget> createState() => _AddTransactionWidgetState();
}

class _AddTransactionWidgetState extends State<AddTransactionWidget> {
  final TextEditingController _beneficiaryTextController =
      TextEditingController();
  final TextEditingController _amountTextController = TextEditingController();

  DateTime _selectedDate = DateTime.now();

  SearchFieldListItem<Beneficiary>? _selectedBeneficiary;

  TransactionDirection _selectedDirection = TransactionDirection.send;

  ExpenseCategory? _expenseCategory;

  @override
  void initState() {
    super.initState();

    if (widget.template != null) {
      _selectedDirection =
          widget.template!.amount > 0
              ? TransactionDirection.receive
              : TransactionDirection.send;
      _amountTextController.text = widget.template!.amount.toString();
      _beneficiaryTextController.text =
          widget.template!.beneficiary.value!.name;
      _selectedBeneficiary = SearchFieldListItem(
        getBeneficiaryName(widget.template!.beneficiary.value!),
        item: widget.template!.beneficiary.value!,
      );
    }
  }

  String getBeneficiaryName(Beneficiary item) {
    return switch (item.type) {
      BeneficiaryType.account => "${item.name} (Account)",
      BeneficiaryType.other => item.name,
    };
  }

  Future<void> _submit(BuildContext context) async {
    final beneficiaryName = _beneficiaryTextController.text;
    if (_selectedBeneficiary == null && beneficiaryName.isEmpty) {
      return;
    }

    Beneficiary? beneficiary = _selectedBeneficiary?.item;
    if (beneficiary == null ||
        getBeneficiaryName(beneficiary) != beneficiaryName) {
      // Add a new beneficiary, if none was selected
      final result = await showDialog<bool>(
        context: context,
        builder:
            (context) => AlertDialog(
              title: const Text("Add Beneficiary"),
              content: Text(
                "The beneficiary '$beneficiaryName' does not exist. Do you want to add it?",
              ),
              actions: [
                TextButton(
                  style: TextButton.styleFrom(
                    textStyle: Theme.of(context).textTheme.labelLarge,
                  ),
                  child: const Text('Add'),
                  onPressed: () => Navigator.of(context).pop(true),
                ),
                TextButton(
                  style: TextButton.styleFrom(
                    textStyle: Theme.of(context).textTheme.labelLarge,
                  ),
                  child: const Text('Cancel'),
                  onPressed: () => Navigator.of(context).pop(false),
                ),
              ],
            ),
      );
      if (result == null || !result) {
        return;
      }

      beneficiary =
          Beneficiary()
            ..name = beneficiaryName
            ..type = BeneficiaryType.other;
      await upsertBeneficiary(beneficiary);
    }

    final factor = switch (_selectedDirection) {
      TransactionDirection.send => -1,
      TransactionDirection.receive => 1,
    };
    final amount = factor * double.parse(_amountTextController.text).abs();
    final transaction =
        Transaction()
          ..account.value = widget.activeAccountItem
          ..beneficiary.value = beneficiary
          ..amount = amount
          ..tags = []
          ..expenseCategory.value = _expenseCategory
          ..date = _selectedDate;
    await upsertTransaction(transaction);

    if (beneficiary.type == BeneficiaryType.account) {
      final otherTransaction =
          Transaction()
            ..account.value = beneficiary.account.value!
            ..beneficiary.value = await getAccountBeneficiary(
              widget.activeAccountItem,
            )
            ..date = _selectedDate
            ..expenseCategory.value = _expenseCategory
            ..amount = -1 * amount;
      await upsertTransaction(otherTransaction);
    }

    widget.onAdd(transaction);
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 16),
      child: ListView(
        shrinkWrap: true,
        children: [
          OutlinedButton(
            onPressed: () async {
              final template = await selectTransactionTemplate(context);
              if (template == null) {
                return;
              }

              _amountTextController.text = template.amount.toString();
              _selectedDirection =
                  template.amount > 0
                      ? TransactionDirection.receive
                      : TransactionDirection.send;
              _selectedBeneficiary = SearchFieldListItem(
                getBeneficiaryName(template.beneficiary.value!),
                item: template.beneficiary.value!,
              );
              _beneficiaryTextController.text = getBeneficiaryName(
                template.beneficiary.value!,
              );
            },
            child: Text("Use template"),
          ),

          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: SegmentedButton<TransactionDirection>(
              segments: [
                ButtonSegment(
                  value: TransactionDirection.send,
                  label: Text("Send"),
                  icon: Icon(Icons.remove),
                ),
                ButtonSegment(
                  value: TransactionDirection.receive,
                  label: Text("Receive"),
                  icon: Icon(Icons.add),
                ),
              ],
              selected: <TransactionDirection>{_selectedDirection},
              multiSelectionEnabled: false,
              onSelectionChanged: (selection) {
                setState(() => _selectedDirection = selection.first);
              },
            ),
          ),

          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: BlocBuilder<CoreCubit, CoreState>(
              builder:
                  (context, state) => SearchField<Beneficiary>(
                    suggestions:
                        state.beneficiaries
                            .where((el) {
                              final bloc = GetIt.I.get<CoreCubit>();
                              if (el.type == BeneficiaryType.account) {
                                return el.account.value?.id.toInt() ==
                                    bloc.activeAccount?.id.toInt();
                              }
                              return true;
                            })
                            .map((el) {
                              return SearchFieldListItem(
                                getBeneficiaryName(el),
                                item: el,
                              );
                            })
                            .toList(),
                    hint: switch (_selectedDirection) {
                      TransactionDirection.send => "Payee",
                      TransactionDirection.receive => "Payer",
                    },
                    controller: _beneficiaryTextController,
                    selectedValue: _selectedBeneficiary,
                    onSuggestionTap: (beneficiary) {
                      setState(() => _selectedBeneficiary = beneficiary);
                    },
                  ),
            ),
          ),

          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: TextField(
              controller: _amountTextController,
              keyboardType: TextInputType.numberWithOptions(
                signed: false,
                decimal: false,
              ),
              decoration: InputDecoration(
                hintText: "Amount",
                icon: Icon(Icons.euro),
              ),
            ),
          ),

          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Text("Date"),
                Padding(
                  padding: EdgeInsets.only(left: 16),
                  child: OutlinedButton(
                    onPressed: () async {
                      final dt = await showDatePicker(
                        context: context,
                        initialDate: _selectedDate,
                        firstDate: DateTime(1),
                        lastDate: DateTime(9999),
                      );
                      if (dt == null) return;

                      setState(() => _selectedDate = dt);
                    },
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Icon(Icons.date_range),
                        Text(formatDateTime(_selectedDate)),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),

          Row(
            children: [
              Text("Expense category"),
              Padding(
                padding: EdgeInsets.only(left: 16),
                child: OutlinedButton(
                  onPressed: () async {
                    final category = await showDialogOrModal(
                      context: context,
                      builder: (_) => AddExpenseCategory(),
                    );
                    if (category == null) {
                      return;
                    }

                    setState(() => _expenseCategory = category);
                  },
                  child: Text(_expenseCategory?.name ?? "None"),
                ),
              ),
            ],
          ),

          Align(
            alignment: Alignment.centerRight,
            child: OutlinedButton(
              onPressed: () => _submit(context),
              child: Text("Add"),
            ),
          ),
        ],
      ),
    );
  }
}