import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
import 'package:prasule/api/category.dart';
import 'package:prasule/api/wallet.dart';
import 'package:prasule/api/wallet_manager.dart';
import 'package:prasule/main.dart';
import 'package:prasule/pw/platformroute.dart';
import 'package:prasule/util/drawer.dart';
import 'package:prasule/util/graphs.dart';
import 'package:prasule/util/utils.dart';
import 'package:prasule/views/settings/settings.dart';
import 'package:prasule/views/setup.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:wheel_chooser/wheel_chooser.dart';

/// Shows data from a [Wallet] in graphs
class GraphView extends StatefulWidget {
  /// Shows data from a [Wallet] in graphs
  const GraphView({super.key});

  @override
  State<GraphView> createState() => _GraphViewState();
}

class _GraphViewState extends State<GraphView> {
  var _selectedDate = DateTime.now();
  Wallet? selectedWallet;
  List<Wallet> wallets = [];
  String? locale;
  bool yearly = true;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    locale ??= Localizations.localeOf(context).languageCode;
  }

  List<double> generateChartData(EntryType type) {
    final d = _selectedDate.add(const Duration(days: 31));
    final data = List<double>.filled(
      yearly ? 12 : DateTime(d.year, d.month, 0).day,
      0,
    );
    if (selectedWallet == null) return [];
    for (var i = 0; i < data.length; i++) {
      final entriesForRange = selectedWallet!.entries.where(
        (element) =>
            ((!yearly)
                ? element.date.month == _selectedDate.month &&
                    element.date.year == _selectedDate.year &&
                    element.date.day == i + 1
                : element.date.month == i + 1 &&
                    element.date.year == _selectedDate.year) &&
            element.type == type,
      );
      var sum = 0.0;
      for (final e in entriesForRange) {
        sum += e.data.amount;
      }
      data[i] = sum;
    }
    return data;
  }

  final availableYears = <WheelChoice<int>>[];

  Future<void> loadWallet() async {
    wallets = await WalletManager.listWallets();
    if (wallets.isEmpty && mounted) {
      unawaited(
        Navigator.of(context)
            .pushReplacement(platformRoute((c) => const SetupView())),
      );
      return;
    }
    selectedWallet = wallets.first;
    availableYears.clear();
    for (final entry in selectedWallet!.entries) {
      if (!availableYears.any((element) => element.value == entry.date.year)) {
        availableYears.add(
          WheelChoice<int>(
            value: entry.date.year,
            title: entry.date.year.toString(),
          ),
        );
      }
    }
    setState(() {});
  }

  int? chartType;
  @override
  void initState() {
    super.initState();
    loadWallet();
    SharedPreferences.getInstance().then((s) {
      chartType = s.getInt("yearlygraph") ?? 1;
      logger.d(chartType);
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        floatingActionButton: Tooltip(
          message: AppLocalizations.of(context).changeDate,
          child: FloatingActionButton(
            child: const Icon(Icons.calendar_month),
            onPressed: () async {
              var selectedYear = _selectedDate.year;
              var selectedMonth = _selectedDate.month;
              await showAdaptiveDialog<void>(
                context: context,
                builder: (c) => AlertDialog.adaptive(
                  title: Text(
                    yearly
                        ? AppLocalizations.of(context).selectYear
                        : AppLocalizations.of(context).selectMonth,
                  ),
                  content: LimitedBox(
                    maxHeight: MediaQuery.of(context).size.width * 0.7,
                    maxWidth: MediaQuery.of(context).size.width * 0.8,
                    child: Wrap(
                      alignment: WrapAlignment.center,
                      spacing: 5,
                      children: [
                        if (!yearly)
                          SizedBox(
                            width: 120,
                            height: 100,
                            child: WheelChooser<int>.choices(
                              onChoiceChanged: (v) {
                                selectedMonth = v as int;
                              },
                              startPosition: _selectedDate.month - 1,
                              choices: List<WheelChoice<int>>.generate(
                                12,
                                (index) => WheelChoice(
                                  value: index + 1,
                                  title: DateFormat.MMMM(locale ?? "en").format(
                                    DateTime(
                                      _selectedDate.year,
                                      index + 1,
                                    ),
                                  ),
                                ),
                              ),
                            ),
                          ),
                        SizedBox(
                          height: 100,
                          width: 80,
                          child: WheelChooser<int>.choices(
                            startPosition: availableYears.indexWhere(
                              (element) => element.value == _selectedDate.year,
                            ),
                            onChoiceChanged: (v) {
                              selectedYear = v as int;
                            },
                            choices: availableYears,
                          ),
                        ),
                      ],
                    ),
                  ),
                  actions: [
                    TextButton(
                      onPressed: () {
                        _selectedDate = DateTime(selectedYear, selectedMonth);
                        Navigator.of(c).pop();
                      },
                      child: Text(AppLocalizations.of(context).ok),
                    ),
                  ],
                ),
              );
              setState(() {});
            },
          ),
        ),
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              Tab(
                child: Text(AppLocalizations.of(context).expenses),
              ),
              Tab(
                child: Text(AppLocalizations.of(context).incomePlural),
              ),
            ],
          ),
          title: DropdownButton<int>(
            value: (selectedWallet == null)
                ? -1
                : wallets.indexOf(
                    wallets.where((w) => w.name == selectedWallet!.name).first,
                  ),
            items: [
              ...wallets.map(
                (e) => DropdownMenuItem(
                  value: wallets.indexOf(
                    e,
                  ),
                  child: Text(e.name),
                ),
              ),
              DropdownMenuItem(
                value: -1,
                child: Text(AppLocalizations.of(context).newWallet),
              ),
            ],
            onChanged: (v) async {
              if (v == null || v == -1) {
                await Navigator.of(context).push(
                  platformRoute(
                    (c) => const SetupView(
                      newWallet: true,
                    ),
                  ),
                );
                wallets = await WalletManager.listWallets();
                logger.i(wallets.length);
                selectedWallet = wallets.last;
                setState(() {});
                return;
              }
              selectedWallet = wallets[v];
              setState(() {});
            },
          ),
          actions: [
            PopupMenuButton(
              itemBuilder: (context) => [
                AppLocalizations.of(context).settings,
                AppLocalizations.of(context).about,
              ].map((e) => PopupMenuItem(value: e, child: Text(e))).toList(),
              onSelected: (value) {
                if (value == AppLocalizations.of(context).settings) {
                  Navigator.of(context)
                      .push(
                    platformRoute(
                      (context) => const SettingsView(),
                    ),
                  )
                      .then((value) async {
                    selectedWallet =
                        await WalletManager.loadWallet(selectedWallet!.name);
                    final s = await SharedPreferences.getInstance();
                    chartType = s.getInt("monthlygraph") ?? 2;
                    setState(() {});
                  });
                } else if (value == AppLocalizations.of(context).about) {
                  showAbout(context);
                }
              },
            ),
          ],
        ),
        drawer: makeDrawer(context, 2),
        body: TabBarView(
          children: [
            // EXPENSE TAB
            SingleChildScrollView(
              child: Center(
                child: (selectedWallet == null)
                    ? const CircularProgressIndicator(
                        strokeWidth: 5,
                      )
                    : SizedBox(
                        width: MediaQuery.of(context).size.width,
                        height: MediaQuery.of(context).size.height,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            SizedBox(
                              width: 200,
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  Text(
                                    AppLocalizations.of(context).monthly,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                  Switch.adaptive(
                                    value: yearly,
                                    onChanged: (v) async {
                                      yearly = v;
                                      final s =
                                          await SharedPreferences.getInstance();
                                      chartType = yearly
                                          ? (s.getInt("yearlygraph") ?? 1)
                                          : (s.getInt("monthlygraph") ?? 2);

                                      setState(() {});
                                    },
                                  ),
                                  Text(
                                    AppLocalizations.of(context).yearly,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            Container(
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(8),
                                boxShadow: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.light)
                                    ? [
                                        BoxShadow(
                                          color: Colors.grey.withOpacity(0.5),
                                          spreadRadius: 3,
                                          blurRadius: 7,
                                          offset: const Offset(
                                            0,
                                            3,
                                          ),
                                        ),
                                      ]
                                    : null,
                                color: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.dark)
                                    ? Theme.of(context)
                                        .colorScheme
                                        .secondaryContainer
                                    : Theme.of(context).colorScheme.surface,
                              ),
                              child: Padding(
                                padding: const EdgeInsets.all(8),
                                child: Column(
                                  children: [
                                    Text(
                                      yearly
                                          ? AppLocalizations.of(context)
                                              .expensesPerYear(
                                              _selectedDate.year,
                                            )
                                          : AppLocalizations.of(context)
                                              .expensesPerMonth(
                                              DateFormat.yMMMM(locale)
                                                  .format(_selectedDate),
                                            ),
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                    const SizedBox(
                                      height: 15,
                                    ),
                                    SizedBox(
                                      width: MediaQuery.of(context).size.width *
                                          0.9,
                                      height:
                                          MediaQuery.of(context).size.height *
                                              0.35,
                                      child: (chartType == null)
                                          ? const CircularProgressIndicator()
                                          : (chartType == 1)
                                              ? ExpensesBarChart(
                                                  currency:
                                                      selectedWallet!.currency,
                                                  date: _selectedDate,
                                                  locale: locale ?? "en",
                                                  yearly: yearly,
                                                  expenseData:
                                                      generateChartData(
                                                    EntryType.expense,
                                                  ),
                                                  incomeData: const [],
                                                )
                                              : Padding(
                                                  padding:
                                                      const EdgeInsets.all(8),
                                                  child: ExpensesLineChart(
                                                    currency: selectedWallet!
                                                        .currency,
                                                    date: _selectedDate,
                                                    locale: locale ?? "en",
                                                    yearly: yearly,
                                                    expenseData:
                                                        generateChartData(
                                                      EntryType.expense,
                                                    ),
                                                    incomeData: const [],
                                                  ),
                                                ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                            const SizedBox(
                              height: 25,
                            ),
                            Container(
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(8),
                                boxShadow: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.light)
                                    ? [
                                        BoxShadow(
                                          color: Colors.grey.withOpacity(0.5),
                                          spreadRadius: 3,
                                          blurRadius: 7,
                                          offset: const Offset(
                                            0,
                                            3,
                                          ),
                                        ),
                                      ]
                                    : null,
                                color: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.dark)
                                    ? Theme.of(context)
                                        .colorScheme
                                        .secondaryContainer
                                    : Theme.of(context).colorScheme.surface,
                              ),
                              width: MediaQuery.of(context).size.width * 0.95,
                              height: MediaQuery.of(context).size.height * 0.4,
                              child: Column(
                                children: [
                                  const SizedBox(
                                    height: 10,
                                  ),
                                  Flexible(
                                    child: Text(
                                      textAlign: TextAlign.center,
                                      yearly
                                          ? AppLocalizations.of(context)
                                              .expensesPerYearCategory(
                                              _selectedDate.year,
                                            )
                                          : AppLocalizations.of(context)
                                              .expensesPerMonthCategory(
                                              DateFormat.yMMMM(locale)
                                                  .format(_selectedDate),
                                            ),
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ),
                                  Padding(
                                    padding: const EdgeInsets.all(6),
                                    child: CategoriesPieChart(
                                      // TODO: better size adaptivity without overflow
                                      locale: locale ?? "en",
                                      symbol: selectedWallet!.currency.symbol,
                                      entries: selectedWallet!.entries
                                          .where(
                                            (element) =>
                                                ((!yearly)
                                                    ? element.date.month ==
                                                            _selectedDate
                                                                .month &&
                                                        element.date.year ==
                                                            _selectedDate.year
                                                    : element.date.year ==
                                                        _selectedDate.year) &&
                                                element.type ==
                                                    EntryType.expense,
                                          )
                                          .toList(),
                                      categories: selectedWallet!.categories,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ),
                      ),
              ),
            ), // Expense Tab END
            SingleChildScrollView(
              child: Center(
                child: (selectedWallet == null)
                    ? const CircularProgressIndicator(
                        strokeWidth: 5,
                      )
                    : SizedBox(
                        width: MediaQuery.of(context).size.width,
                        height: MediaQuery.of(context).size.height,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            SizedBox(
                              width: 200,
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  Text(
                                    AppLocalizations.of(context).monthly,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                  Switch.adaptive(
                                    value: yearly,
                                    onChanged: (v) async {
                                      yearly = v;
                                      final s =
                                          await SharedPreferences.getInstance();
                                      chartType = yearly
                                          ? (s.getInt("yearlygraph") ?? 1)
                                          : (s.getInt("monthlygraph") ?? 2);

                                      setState(() {});
                                    },
                                  ),
                                  Text(
                                    AppLocalizations.of(context).yearly,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            Container(
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(8),
                                boxShadow: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.light)
                                    ? [
                                        BoxShadow(
                                          color: Colors.grey.withOpacity(0.5),
                                          spreadRadius: 3,
                                          blurRadius: 7,
                                          offset: const Offset(
                                            0,
                                            3,
                                          ),
                                        ),
                                      ]
                                    : null,
                                color: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.dark)
                                    ? Theme.of(context)
                                        .colorScheme
                                        .secondaryContainer
                                    : Theme.of(context).colorScheme.surface,
                              ),
                              child: Padding(
                                padding: const EdgeInsets.all(8),
                                child: Column(
                                  children: [
                                    Text(
                                      yearly
                                          ? AppLocalizations.of(context)
                                              .incomePerYear(
                                              _selectedDate.year,
                                            )
                                          : AppLocalizations.of(context)
                                              .incomePerMonth(
                                              DateFormat.yMMMM(locale)
                                                  .format(_selectedDate),
                                            ),
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                    const SizedBox(
                                      height: 15,
                                    ),
                                    SizedBox(
                                      width: MediaQuery.of(context).size.width *
                                          0.9,
                                      height:
                                          MediaQuery.of(context).size.height *
                                              0.35,
                                      child: (chartType == null)
                                          ? const CircularProgressIndicator()
                                          : (chartType == 1)
                                              ? ExpensesBarChart(
                                                  currency:
                                                      selectedWallet!.currency,
                                                  date: _selectedDate,
                                                  locale: locale ?? "en",
                                                  yearly: yearly,
                                                  expenseData: const [],
                                                  incomeData: generateChartData(
                                                    EntryType.income,
                                                  ),
                                                )
                                              : Padding(
                                                  padding:
                                                      const EdgeInsets.all(8),
                                                  child: ExpensesLineChart(
                                                    currency: selectedWallet!
                                                        .currency,
                                                    date: _selectedDate,
                                                    locale: locale ?? "en",
                                                    yearly: yearly,
                                                    expenseData: const [],
                                                    incomeData:
                                                        generateChartData(
                                                      EntryType.income,
                                                    ),
                                                  ),
                                                ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                            const SizedBox(
                              height: 25,
                            ),
                            Container(
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(8),
                                boxShadow: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.light)
                                    ? [
                                        BoxShadow(
                                          color: Colors.grey.withOpacity(0.5),
                                          spreadRadius: 3,
                                          blurRadius: 7,
                                          offset: const Offset(
                                            0,
                                            3,
                                          ),
                                        ),
                                      ]
                                    : null,
                                color: (MediaQuery.of(context)
                                            .platformBrightness ==
                                        Brightness.dark)
                                    ? Theme.of(context)
                                        .colorScheme
                                        .secondaryContainer
                                    : Theme.of(context).colorScheme.surface,
                              ),
                              width: MediaQuery.of(context).size.width * 0.95,
                              height: MediaQuery.of(context).size.height * 0.4,
                              child: Column(
                                children: [
                                  const SizedBox(
                                    height: 10,
                                  ),
                                  Flexible(
                                    child: Text(
                                      yearly
                                          ? AppLocalizations.of(context)
                                              .incomePerYearCategory(
                                              _selectedDate.year,
                                            )
                                          : AppLocalizations.of(context)
                                              .incomePerMonthCategory(
                                              DateFormat.yMMMM(locale)
                                                  .format(_selectedDate),
                                            ),
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ),
                                  Padding(
                                    padding: const EdgeInsets.all(6),
                                    child: CategoriesPieChart(
                                      locale: locale ?? "en",
                                      symbol: selectedWallet!.currency.symbol,
                                      entries: selectedWallet!.entries
                                          .where(
                                            (element) =>
                                                ((!yearly)
                                                    ? element.date.month ==
                                                            _selectedDate
                                                                .month &&
                                                        element.date.year ==
                                                            _selectedDate.year
                                                    : element.date.year ==
                                                        _selectedDate.year) &&
                                                element.type ==
                                                    EntryType.income,
                                          )
                                          .toList(),
                                      categories: selectedWallet!.categories,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ),
                      ),
              ),
            ), // Income Tab END
          ],
        ),
      ),
    );
  }
}
