import 'dart:convert';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:helpers/helpers/print.dart';
import 'package:rluv/global/api.dart';
import 'package:rluv/models/budget.dart';
import 'package:rluv/models/budget_category_model.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../models/family_model.dart';
import '../models/shared_note.dart';
import '../models/transaction_model.dart';
import '../models/user.dart';

class Store {
  static final Store _instance = Store._internal();
  bool _initDone = false;
  SharedPreferences? prefs;

  factory Store() {
    if (_instance._initDone) {
      return _instance;
    }
    _instance._initDone = true;
    SharedPreferences.getInstance().then(
      (value) => _instance.prefs = value,
    );
    _instance.dashboardProvider =
        StateNotifierProvider<DashBoardStateNotifier, Map<String, dynamic>?>(
      (ref) {
        final family = ref.watch(_instance.familyProvider).valueOrNull;
        return DashBoardStateNotifier(family);
      },
    );
    // _instance.dashboardProvider = FutureProvider<Map<String, dynamic>?>(
    //   (ref) async {
    //     final family = await ref.watch(_instance.familyProvider.future);
    //     return Api().get("dashboard/${family.id}");
    //   },
    // );
    _instance.budgetProvider = Provider<Budget?>(
      (ref) {
        final dash = ref.watch(_instance.dashboardProvider);
        if (dash == null) return null;
        final budgetData = dash['budget'] as Map<String, dynamic>?;
        if (budgetData == null) return null;
        return Budget.fromJson(budgetData);
      },
    );
    _instance.budgetCategoriesProvider = Provider<List<BudgetCategory>>((ref) {
      final dash = ref.watch(_instance.dashboardProvider);
      if (dash == null) return [];
      final categoriesData = dash['budget_categories'] as List<dynamic>;
      final categories = categoriesData
          .map(
            (e) => BudgetCategory.fromJson(e as Map<String, dynamic>),
          )
          .toList();
      if (_instance.prefs != null) {
        final budgetJson = jsonEncode({'budget_categories': categoriesData});
        printBlue('updated prefs stored categories');
        _instance.prefs!.setString('budget_categories', budgetJson);
      }
      return categories;
    });
    _instance.transactionsProvider = Provider<List<Transaction>>((ref) {
      final dash = ref.watch(_instance.dashboardProvider);
      if (dash == null) return [];
      final transactions = dash['transactions'] as List<dynamic>;
      return transactions
          .map(
            (e) => Transaction.fromJson(e as Map<String, dynamic>),
          )
          .toList();
    });
    return _instance;
  }

  Store._internal();

  final FutureProvider<User> userProvider = FutureProvider<User>(
    (ref) {
      return User(
        id: 0,
        budgetId: 1,
        createdAt: DateTime.now(),
        familyId: 1,
        lastActivityAt: DateTime.now(),
        name: 'TEMP',
        updatedAt: DateTime.now(),
      );
    },
  );

  final FutureProvider<FamilyModel> familyProvider =
      FutureProvider<FamilyModel>((ref) => FamilyModel(
          id: 1,
          budgetId: 1,
          createdAt: DateTime.now(),
          updatedAt: DateTime.now()));

  late final Provider<List<BudgetCategory>> budgetCategoriesProvider;
  late final Provider<Budget?> budgetProvider;
  late final Provider<List<Transaction>> transactionsProvider;
  late final Provider<List<SharedNote>> sharedNotesProvider;
  // late final FutureProvider<Map<String, dynamic>?> dashboardProvider;

  late final StateNotifierProvider<DashBoardStateNotifier,
      Map<String, dynamic>?> dashboardProvider;
  void fetchDashboard() {}
}

class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
  DashBoardStateNotifier(FamilyModel? family) : super(null) {
    fetchDashboard(family);
  }

  Future fetchDashboard(FamilyModel? family) async {
    if (family == null) {
      printPink('Unable to get dashboard');
      return;
    }
    printAmber('Fetching dashboard');
    state = await Api().get("dashboard/${family.id}");
  }

  void update(Map<String, dynamic> data) {
    if (state == null) {
      printPink('Cant update data, state is null');
      return;
    }
    if (data.keys.length != 1 || data.values.length != 1) {
      throw Exception('Only one key/val used in update');
    }
    final key = data.keys.first;
    switch (key) {
      case 'transactions':
      case 'budget_categories':
        final subStateList = state![key] as List<dynamic>;
        final subStateListObj = subStateList
            .map(
              (e) => e as Map<String, dynamic>,
            )
            .toList();
        subStateListObj.removeWhere(
          (element) =>
              element['id'] ==
              (data.values.first as Map<String, dynamic>)['id'],
        );
        subStateListObj.add(data.values.first);

        final newState = state;
        newState![key] = subStateListObj;
        state = {...newState};
        // printBlue(state);
        break;
      default:
        break;
    }
  }

  void add(Map<String, dynamic> data) {
    if (state == null) {
      printPink('Cant add data, state is null');
      return;
    }
    if (data.keys.length != 1 || data.values.length != 1) {
      throw Exception('Only one key/val used in add');
    }
    final key = data.keys.first;
    switch (key) {
      case 'transactions':
      case 'budget_categories':
        final subStateList = state![key] as List<dynamic>;
        final newState = state;
        subStateList.add(data.values.first);
        newState![key] = subStateList;
        state = {...newState};
        // printBlue(state);
        break;
      default:
        break;
    }
  }
}