import '../about/external/data/Commitment.dart';
import '../about/internal/application/Standing.dart';
import 'DebtEngine.dart';
import 'Thresholds.dart';

/// Standing is computed continuously and drives real consequences. It is
/// derived, never set — there is no way to talk your way up a tier.
class StandingEngine {
  /// The standing implied by the current debt and the missed-non-negotiable
  /// count. Sick mode never escalates: strictness must never be the response
  /// to someone who is actually struggling.
  static Standing evaluate(
    double debtScore, {
    int missedNonNegotiables = 0,
    bool sickMode = false,
    bool distressed = false,
  }) {
    if (sickMode || distressed) {
      return Standing.Good;
    }

    if (debtScore >= Thresholds.lockdownThreshold) {
      return Standing.Lockdown;
    }

    if (debtScore >= Thresholds.groundedThreshold ||
        missedNonNegotiables >= Thresholds.nonNegotiableMissesForGrounded) {
      return Standing.Grounded;
    }

    if (debtScore >= Thresholds.warnedThreshold) {
      return Standing.Warned;
    }

    return Standing.Good;
  }

  /// Evaluate straight from the commitment list.
  static Standing evaluateFor(
    List<Commitment> commitments, {
    bool sickMode = false,
    bool distressed = false,
    DateTime? now,
  }) {
    return evaluate(
      DebtEngine.totalDebt(commitments, now: now),
      missedNonNegotiables: DebtEngine.missedNonNegotiables(commitments),
      sickMode: sickMode,
      distressed: distressed,
    );
  }

  /// Whether a new commitment of this class may be created right now.
  static bool permitsNewCommitment(Standing standing, {bool elective = false}) {
    if (elective) {
      return canAddElectives(standing);
    }
    return canAddCommitments(standing);
  }

  /// Grounded replaces the home screen with the overdue queue — you do not get
  /// to look at your nice plans, only at your mess.
  static bool showsOverdueQueueAsHome(Standing standing) {
    return standing == Standing.Grounded || standing == Standing.Lockdown;
  }

  /// Lockdown puts a blocking interstitial in front of the app that must be
  /// cleared one item at a time.
  static bool blocksAppOnOpen(Standing standing) {
    return standing == Standing.Lockdown;
  }

  /// Whether the accountability partner is auto-notified at this tier.
  static bool notifiesPartner(Standing standing) {
    return standing == Standing.Grounded || standing == Standing.Lockdown;
  }

  /// Debt still to shed before dropping a tier. Zero when already at Good.
  static double debtToNextTierDown(double debtScore, Standing standing) {
    switch (standing) {
      case Standing.Lockdown:
        return debtScore - Thresholds.lockdownThreshold;
      case Standing.Grounded:
        return debtScore - Thresholds.groundedThreshold;
      case Standing.Warned:
        return debtScore - Thresholds.warnedThreshold;
      case Standing.Good:
        return 0;
    }
  }
}
