import 'package:drift/drift.dart';

import '../Entities/drift_database.dart';
import '../Entities/time_frame_enum.dart';
import '../Services/database_service.dart';

/// Funktionen zum interagieren mit der Datenbank für die Transaktionen
class RecurringTransactionRepository {
  final AppDatabase _db = DatabaseService().database;

  /// Fügt eine neue wiederkehrende Transaktion zur Datenbank hinzu
  Future<RecurringTransaction?> add(
    final RecurringTransactionsCompanion recurringTransaction,
  ) async {
    final int id = await _db
        .into(_db.recurringTransactions)
        .insert(recurringTransaction);
    return find(id);
  }

  /// Aktualisiert eine wiederkehrende Transaktion in der Datenbank
  Future<bool> update(
    final RecurringTransactionsCompanion recurringTransaction,) {
    final RecurringTransactionsCompanion recurringTransactionToUpdate =
    RecurringTransactionsCompanion(
      id: recurringTransaction.id,
      name: recurringTransaction.name,
      startDate: recurringTransaction.startDate,
      timeFrame: recurringTransaction.timeFrame,
      amount: recurringTransaction.amount,
      accountId: recurringTransaction.accountId,
      updatedAt: Value(DateTime.now()),
    );

    return _db
        .update(_db.recurringTransactions)
        .replace(recurringTransactionToUpdate);
  }

  /// Entfernt eine wiederkehrende Transaktion aus der Datenbank
  Future<int> remove(final RecurringTransaction recurringTransaction) =>
      (_db.delete(
        _db.recurringTransactions,
      )..where((final t) => t.id.equals(recurringTransaction.id))).go();

  /// Sucht eine wiederkehrende Transaktion anhand seiner Id aus der Datenbank
  Future<RecurringTransaction?> find(final int id) => (_db.select(
    _db.recurringTransactions,
  )..where((final t) => t.id.equals(id))).getSingleOrNull();

  /// Sucht wiederkehrende Transaktionen anhand der gegebenen Parameter
  /// aus der Datenbank
  Future<List<RecurringTransaction>> findBy({
    final int? id,
    final String? name,
    final DateTime? startDate,
    final DateTime? startDateBefore,
    final DateTime? startDateAfter,
    final TimeFrameEnum? timeFrame,
    final double? amount,
    final double? amountMin,
    final double? amountMax,
    final Account? account,
    final String? orderBy,
  }) {
    final SimpleSelectStatement<
      $RecurringTransactionsTable,
      RecurringTransaction
    >
    query = _db.select(_db.recurringTransactions);

    if (id != null) {
      query.where((final t) => t.id.equals(id));
    }

    if (name != null && name.isNotEmpty) {
      query.where((final t) => t.name.like('%$name%'));
    }

    if (startDate != null) {
      query.where((final t) => t.startDate.equals(startDate));
    }

    if (startDateAfter != null) {
      query.where((final t) => t.startDate.isBiggerThanValue(startDateAfter));
    }

    if (startDateBefore != null) {
      query.where((final t) => t.startDate.isSmallerThanValue(startDateBefore));
    }

    if (timeFrame != null) {
      query.where((final t) => t.timeFrame.equals(timeFrame.index));
    }

    if (amount != null) {
      query.where((final t) => t.amount.equals(amount));
    }

    if (amountMin != null) {
      query.where((final t) => t.amount.isBiggerThanValue(amountMin));
    }

    if (amountMax != null) {
      query.where((final t) => t.amount.isSmallerThanValue(amountMax));
    }

    if (account != null) {
      query.where((final t) => t.accountId.equals(account.id));
    }

    if (orderBy != null) {
      switch (orderBy) {
        case 'nameAsc':
          query.orderBy([(final t) => OrderingTerm.asc(t.name)]);
        case 'nameDesc':
          query.orderBy([(final t) => OrderingTerm.desc(t.name)]);
        case 'amountAsc':
          query.orderBy([(final t) => OrderingTerm.asc(t.amount)]);
        case 'amountDesc':
          query.orderBy([(final t) => OrderingTerm.desc(t.amount)]);
        case 'startDateAsc':
          query.orderBy([(final t) => OrderingTerm.asc(t.startDate)]);
        case 'startDateDesc':
          query.orderBy([(final t) => OrderingTerm.desc(t.startDate)]);
      }
    }

    return query.get();
  }
}
