import '../../about/external/data/Commitment.dart';
import '../../about/external/data/pages/request/CommitmentsRequest.dart';
import '../../about/external/data/pages/request/PageAndSort.dart';
import '../../about/external/data/pages/request/Pageable.dart';
import '../../about/external/data/pages/request/Sort.dart';
import '../../about/external/data/pages/response/CommitmentPage.dart';
import '../../about/external/initial/CommitmentRequest.dart';
import '../../about/internal/application/CapacityProfile.dart';
import '../../utils/CapacityEngine.dart';
import '../parent/ParentViewModel.dart';
import 'ConnectNewCommitment.dart';

class ViewNewCommitment extends ParentViewModel {
  ConnectNewCommitment connection;

  ViewNewCommitment(super.context, this.connection);

  /// Surfaces the learned multiplier for the category so the estimate field
  /// can show what the app actually expects, rather than silently overriding.
  void resolveMultiplier(String category) async {
    final CapacityProfile profile =
        await getDataManager().getCapacityProfile();

    connection.onMultiplierResolved(profile.multiplierFor(category));
  }

  /// The capacity gate. Chronic overdue is usually overcommitment misdiagnosed
  /// as laziness, so the plan is checked against what history says actually
  /// gets done before anything is accepted.
  void save(CommitmentRequest request, Commitment candidate) async {
    if (!await hasNetwork(() => save(request, candidate))) return;

    showLoading("Checking your day");

    try {
      final DateTime day = candidate.dueStart ?? DateTime.now();

      final response = await getDataManager().getTodayPlan(CommitmentsRequest(
        day: day.toIso8601String(),
        query: PageAndSort(
          sort: Sort('asc', 'dueStart'),
          page: Pageable(0, 0, 100, 0),
        ),
      ));

      final CommitmentPage page = CommitmentPage.fromJson(response.data);

      final CapacityProfile profile =
          await getDataManager().getCapacityProfile();

      final List<Commitment> proposed = <Commitment>[
        ...page.content,
        candidate,
      ];

      final CapacityVerdict verdict =
          CapacityEngine.check(proposed, profile, day.weekday);

      if (verdict.blocked) {
        closeLoading();
        connection.onCapacityBlocked(verdict);
        return;
      }

      await getDataManager().saveCommitmentEntry(request);

      closeLoading();

      connection.onSaved();
    } catch (e) {
      handleError(
          e, () => save(request, candidate), () => dismissError(), "Retry");
    }
  }

  /// Saving past a capacity block, which is only reachable after the user has
  /// seen exactly how much they are over by.
  void saveAnyway(CommitmentRequest request) async {
    if (!await hasNetwork(() => saveAnyway(request))) return;

    showLoading("Saving");

    try {
      await getDataManager().saveCommitmentEntry(request);

      closeLoading();

      connection.onSaved();
    } catch (e) {
      handleError(e, () => saveAnyway(request), () => dismissError(), "Retry");
    }
  }
}
