// Flutter
import 'package:flutter/material.dart';
import 'package:flutter_expense_tracker/db.dart';

// Local
import '/models/expense.dart';
import '/models/frequency.dart';

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

  @override
  State<ExpensePage> createState() => _ExpensePageState();
}

class _ExpensePageState extends State<ExpensePage> {
  refresh() {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    return FutureBuilder<List<Expense>>(
        future: DatabaseHelper.instance.getExpenses(),
        builder: (BuildContext context, AsyncSnapshot<List<Expense>> snapshot) {
          if (!snapshot.hasData) {
            return Center(child: Text('Loading...'));
          }
          snapshot.data!.sort(
            (a, b) => (b.calcComparableCost() - a.calcComparableCost()).toInt(),
          );
          return snapshot.data!.isEmpty
              ? Text(
                  "Add expenses to get started.",
                  softWrap: true,
                )
              : ListView.builder(
                  itemCount: snapshot.data!.length,
                  itemBuilder: (_, index) {
                    List<Expense> expenses = snapshot.data!;
                    final Expense curr = expenses[index];
                    final String estimateSymbolYearly = curr
                                .frequency.timesPerYear
                                .toStringAsFixed(2)
                                .endsWith(".00") &&
                            curr
                                .calcComparableCost()
                                .toStringAsFixed(3)
                                .endsWith("0")
                        ? ""
                        : "~";
                    final String estimateSymbolDaily = curr.frequency.numDays
                                .toStringAsFixed(2)
                                .endsWith(".00") &&
                            curr
                                .calcComparableCostDaily()
                                .toStringAsFixed(3)
                                .endsWith("0")
                        ? ""
                        : "~";
                    return Padding(
                      padding: const EdgeInsets.all(4.0),
                      child: Dismissible(
                        key: Key(curr.id!.toString()),
                        background: Container(
                          color: Colors.red,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              Icon(Icons.delete),
                              Text("Delete"),
                            ],
                          ),
                        ),
                        secondaryBackground: Container(
                          color: Colors.orange,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: [
                              Text("Edit"),
                              Icon(Icons.edit),
                            ],
                          ),
                        ),
                        onDismissed: (direction) {
                          setState(() {
                            expenses.remove(curr);
                            switch (direction) {
                              case DismissDirection.startToEnd:
                                DatabaseHelper.instance.removeExpense(curr.id!);
                                break;
                              case DismissDirection.endToStart:
                                // Open an edit dialog, then remove the item from the list.
                                showDialog(
                                  context: context,
                                  builder: (_) => AlertDialog(
                                    content: ExpenseInputDialog(
                                      notifyParent: refresh,
                                      expense: curr,
                                    ),
                                  ),
                                );
                                break;
                              default:
                                UnimplementedError(
                                  "Direction ${direction.toString()} not recognized.",
                                );
                            }
                          });
                        },
                        child: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(4),
                            color: theme.colorScheme.onPrimary,
                          ),
                          child: Padding(
                            padding: const EdgeInsets.all(4.0),
                            child: Row(
                              mainAxisSize: MainAxisSize.max,
                              children: [
                                Column(
                                  mainAxisSize: MainAxisSize.min,
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      curr.name,
                                      style: TextStyle(fontSize: 20.0),
                                    ),
                                    Text(
                                      "${curr.cost.toStringAsFixed(2)} ${curr.frequency.title}",
                                      style: TextStyle(fontSize: 12.0),
                                    ),
                                  ],
                                ),
                                Expanded(
                                  child: Center(
                                    child: Text(
                                      curr.description,
                                      style: TextStyle(
                                        fontSize: 12.0,
                                      ),
                                      softWrap: true,
                                      textAlign: TextAlign.center,
                                    ),
                                  ),
                                ),
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.end,
                                  children: [
                                    //if (curr.frequency != Frequency.daily)
                                    Text(
                                      "$estimateSymbolDaily${curr.calcComparableCostDaily().toStringAsFixed(2)} ${Frequency.daily.title}",
                                      style: TextStyle(fontSize: 12.0),
                                    ),
                                    //if (curr.frequency != Frequency.yearly)
                                    Text(
                                      "$estimateSymbolYearly${curr.calcComparableCost().toStringAsFixed(2)} ${Frequency.yearly.title}",
                                      style: TextStyle(fontSize: 12.0),
                                    ),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    );
                  },
                );
        });
  }
}

class ExpenseInputDialog extends StatefulWidget {
  final Function() notifyParent;
  final Expense? expense;

  const ExpenseInputDialog({
    super.key,
    required this.notifyParent,
    this.expense,
  });

  @override
  State<ExpenseInputDialog> createState() => _ExpenseInputDialogState();
}

class _ExpenseInputDialogState extends State<ExpenseInputDialog> {
  final _expenseFormKey = GlobalKey<FormState>();

  int? _id;
  String _name = "";
  double _cost = 0;
  Frequency _freq = Frequency.monthly;
  String _desc = "";

  @override
  Widget build(BuildContext context) {
    if (widget.expense != null) {
      _id = widget.expense!.id;
      _name = widget.expense!.name;
      _cost = widget.expense!.cost;
      _freq = widget.expense!.frequency;
      _desc = widget.expense!.description;
    }

    return Column(
      // prevent AlertDialog from taking full vertical height.
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          alignment: FractionalOffset.topRight,
          child: IconButton(
            onPressed: () {
              if (widget.expense != null) {
                setState(() {
                  DatabaseHelper.instance.addExpense(widget.expense!);
                  widget.notifyParent();
                });
              }
              Navigator.of(context).pop();
            },
            icon: Icon(Icons.clear),
          ),
        ),
        AlertDialog(
          insetPadding: EdgeInsets.all(0),
          title: Center(
            child: widget.expense == null
                ? Text("New Expense")
                : Text("Edit Expense"),
          ),
          content: FutureBuilder<List<Expense>>(
              future: DatabaseHelper.instance.getExpenses(),
              builder: (BuildContext context,
                  AsyncSnapshot<List<Expense>> snapshot) {
                if (!snapshot.hasData) {
                  return Center(child: Text('Loading...'));
                }
                List<Expense> expenses = snapshot.data!;
                return Form(
                  key: _expenseFormKey,
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      TextFormField(
                        keyboardType: TextInputType.text,
                        textCapitalization: TextCapitalization.words,
                        decoration: InputDecoration(
                          labelText: "Name",
                          hintText: "Example: Red Pocket",
                          hintStyle: TextStyle(fontSize: 10.0),
                          errorStyle: TextStyle(fontSize: 10.0),
                        ),
                        initialValue: _name,
                        validator: (value) {
                          if (value!.isEmpty) {
                            return "Name must be provided.";
                          }
                          if (!expenses
                              .every((expense) => expense.name != value)) {
                            return "Name must be unique, already in use.";
                          }
                          return null;
                        },
                        onSaved: (value) {
                          _name = value!;
                        },
                      ),
                      TextFormField(
                        keyboardType:
                            TextInputType.numberWithOptions(decimal: true),
                        decoration: InputDecoration(
                          labelText: "Cost",
                          hintText: "Example: 10.00",
                          hintStyle: TextStyle(fontSize: 10.0),
                          errorStyle: TextStyle(fontSize: 10.0),
                        ),
                        initialValue: _cost != 0 ? _cost.toString() : "",
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            return "Cost must be provided.";
                          }
                          if (double.parse(value) < 0) {
                            return "Please use the Income page rather than having negative expenses.";
                          }
                          if (double.parse(value) < 0.01) {
                            return "Cost must be one hundreth (0.01) or higher.";
                          }
                          if (double.tryParse(value) == null) {
                            return "Cost must be a valid number.";
                          }
                          return null;
                        },
                        onSaved: (value) {
                          _cost = double.parse(value!);
                        },
                      ),
                      DropdownButtonFormField(
                        items: Frequency.values
                            .map(
                              (freq) => DropdownMenuItem(
                                value: freq,
                                child: Row(
                                  children: [
                                    Text(
                                      freq.title,
                                    ),
                                    Padding(
                                      padding: EdgeInsets.all(1.0),
                                      child: Text(
                                        " (${freq.hint})",
                                        style: TextStyle(fontSize: 10.0),
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            )
                            .toList(),
                        value: _freq,
                        decoration: InputDecoration(
                          labelText: "Frequency",
                          errorStyle: TextStyle(fontSize: 10.0),
                        ),
                        validator: (value) {
                          if (value == null) {
                            return "Frequency must be provided.";
                          }
                          if (!Frequency.values.contains(value)) {
                            return "Value not valid.";
                          }
                          return null;
                        },
                        onChanged: (value) {
                          _freq = value!;
                        },
                      ),
                      TextFormField(
                        keyboardType: TextInputType.text,
                        textCapitalization: TextCapitalization.sentences,
                        decoration: InputDecoration(
                          labelText: "Description",
                          hintText:
                              "Example: 1GB data with unlimited talk & text.",
                          hintStyle: TextStyle(fontSize: 8.0),
                          errorStyle: TextStyle(fontSize: 10.0),
                        ),
                        initialValue: _desc,
                        validator: (value) {
                          return null;
                        },
                        onSaved: (value) {
                          _desc = value!;
                        },
                      ),
                    ],
                  ),
                );
              }),
          actions: [
            Center(
              child: ElevatedButton.icon(
                onPressed: () {
                  if (_expenseFormKey.currentState!.validate()) {
                    _expenseFormKey.currentState!.save();
                    setState(() {
                      Expense expense = Expense(
                        id: _id,
                        name: _name,
                        cost: _cost,
                        frequency: _freq,
                        description: _desc,
                      );
                      if (_id != null) {
                        DatabaseHelper.instance.updateExpense(
                          expense,
                        );
                      } else {
                        DatabaseHelper.instance.addExpense(
                          expense,
                        );
                      }
                    });
                    widget.notifyParent();
                    Navigator.of(context).pop();
                  }
                },
                icon: Icon(Icons.save),
                label: Text('Submit'),
              ),
            )
          ],
        ),
      ],
    );
  }
}