import type { TrustState } from "@app/shared-types";

export interface DecayProfile {
  halfLifeDays: number;
  staleAfterDays: number;
}

export interface TrustInput {
  confidence: number;
  verifiedByUser: boolean;
  lastVerifiedAt: Date | string | null;
  quantity: number;
  updatedAt: Date | string;
}

export interface InventoryItemLike {
  confidence: number;
  verifiedByUser: boolean;
  lastVerifiedAt: Date | string | null;
  quantity: number;
  updatedAt: Date | string;
  depletedAt?: Date | string | null;
}

export interface TrustResult {
  state: TrustState;
  score: number; // 0–100
}

const DEFAULT_DECAY: DecayProfile = { halfLifeDays: 7, staleAfterDays: 30 };

/**
 * Deterministic exponential decay of confidence.
 * Decay affects TRUST only, never edibility (mjölkprincipen D-035).
 */
export function applyDecay(
  confidence: number,
  elapsedDays: number,
  profile: DecayProfile = DEFAULT_DECAY,
): number {
  if (elapsedDays <= 0) return confidence;
  if (elapsedDays >= profile.staleAfterDays) return 0;
  const factor = Math.pow(0.5, elapsedDays / profile.halfLifeDays);
  return Math.max(0, confidence * factor);
}

/**
 * Compute the trust state of an inventory item.
 *
 * - unverified: quantity is present but never verified.
 * - trusted: user verified or high confidence and recently touched.
 * - decaying: confidence is dropping / not verified for a while.
 * - stale: very old, unverified, or confidence critically low.
 *
 * Decay affects TRUST, not edibility (mjölkprincipen D-035).
 */
export function computeTrust(
  input: TrustInput,
  now: Date = new Date(),
  profile: DecayProfile = DEFAULT_DECAY,
): TrustResult {
  const nowMs = now.getTime();
  const lastVerified = input.lastVerifiedAt ? new Date(input.lastVerifiedAt).getTime() : null;
  const updated = new Date(input.updatedAt).getTime();
  const referenceMs = lastVerified ?? updated;
  const elapsedDays = (nowMs - referenceMs) / 86_400_000;
  const daysSinceUpdate = (nowMs - updated) / 86_400_000;

  // Decay confidence deterministically from the profile.
  const effectiveConfidence = applyDecay(input.confidence, elapsedDays, profile);

  // Base score from effective confidence (0–80 points)
  let score = Math.round(effectiveConfidence * 80);

  // Verification bonus (0–20 points) – verification age is already reflected by decay,
  // but a known user-verified item retains a small pedigree bonus.
  if (input.verifiedByUser && elapsedDays <= 7) {
    score += 20;
  } else if (input.verifiedByUser && elapsedDays <= 30) {
    score += 10;
  } else if (input.verifiedByUser) {
    score += 5;
  }

  // Additional staleness penalty when update is old.
  if (daysSinceUpdate > profile.staleAfterDays) {
    score -= 20;
  } else if (daysSinceUpdate > 14) {
    score -= Math.min(15, Math.floor((daysSinceUpdate - 14) / 7) * 5);
  }
  if (input.quantity <= 0) {
    score -= 10; // depleted items are less interesting for trust
  }

  score = Math.max(0, Math.min(100, score));

  let state: TrustState;
  if (score >= 80) {
    state = "trusted";
  } else if (score >= 60) {
    state = "trusted";
  } else if (score >= 30) {
    state = "decaying";
  } else if (lastVerified === null && daysSinceUpdate <= 1) {
    state = "unverified";
  } else {
    state = "stale";
  }

  return { state, score };
}

/** Convenience wrapper that returns just the state for an inventory row. */
export function itemTrustState(
  item: InventoryItemLike,
  now?: Date,
  profile?: DecayProfile,
): TrustState {
  return computeTrust(item, now, profile).state;
}

export interface HouseholdTrustInput {
  items: InventoryItemLike[];
  /** Antal justeringstransaktioner senaste 30 dagarna (korrigeringsfrekvens). */
  correctionCount30d: number;
  /** Totalt antal transaktioner senaste 30 dagarna (används för korrigeringsfrekvens). */
  transactionCount30d: number;
}

export interface HouseholdTrustResult {
  score: number; // 0–100
  status: "up_to_date" | "needs_check" | "uncertain";
}

export const TRUST_STATUS_THRESHOLDS = {
  upToDate: 80,
  needsCheck: 50,
} as const;

/**
 * Deterministisk household trust score 0–100.
 *
 * Viktade komponenter (Fas 2 §5.3):
 * - 25% verifierade poster (verifiedByUser)
 * - 25% ålder på senaste kontroll (nyare = bättre)
 * - 20% andel uppskattade mängder (lägre confidence ger mer osäkerhet)
 * - 15% poster som borde vara slut (låg quantity utan depletedAt straffar)
 * - 15% korrigeringsfrekvens (fler korrigeringar = lägre förtroende)
 *
 * Decay påverkar FORTROENDE, inte ätbarhet.
 */
export function householdTrustScore(
  input: HouseholdTrustInput,
  now: Date = new Date(),
): HouseholdTrustResult {
  const items = input.items.filter((i) => i.quantity > 0 && !i.depletedAt);
  if (items.length === 0) {
    return { score: 100, status: "up_to_date" };
  }

  const nowMs = now.getTime();

  // 1. Andel verifierade (0–100)
  const verifiedRatio = items.filter((i) => i.verifiedByUser).length / items.length;
  const verifiedScore = verifiedRatio * 100;

  // 2. Ålder på senaste kontroll (0–100, 100 = alla kontrollerade inom 7 dagar)
  const ageScore =
    items.reduce((sum, i) => {
      const verifiedMs = i.lastVerifiedAt ? new Date(i.lastVerifiedAt).getTime() : null;
      const referenceMs = verifiedMs ?? new Date(i.updatedAt).getTime();
      const days = Math.max(0, (nowMs - referenceMs) / 86_400_000);
      return sum + Math.max(0, 100 - (days / 30) * 100);
    }, 0) / items.length;

  // 3. Andel uppskattade mängder (0–100, 100 = alla har confidence 1)
  const confidenceScore =
    items.reduce((sum, i) => sum + Math.min(1, Math.max(0, i.confidence)), 0) / items.length * 100;

  // 4. Poster som borde vara slut (0–100, 100 = inga låga kvantiteter)
  const depletionScore =
    items.reduce((sum, i) => {
      const qty = i.quantity;
      if (qty <= 0) return sum + 0;
      if (qty < 0.2) return sum + 40;
      if (qty < 0.5) return sum + 70;
      return sum + 100;
    }, 0) / items.length;

  // 5. Korrigeringsfrekvens (0–100, 100 = inga korrigeringar)
  const correctionRatio =
    input.transactionCount30d > 0
      ? input.correctionCount30d / input.transactionCount30d
      : 0;
  const correctionScore = Math.max(0, 100 - correctionRatio * 200);

  const score = Math.round(
    verifiedScore * 0.25 +
      ageScore * 0.25 +
      confidenceScore * 0.20 +
      depletionScore * 0.15 +
      correctionScore * 0.15,
  );

  const clamped = Math.max(0, Math.min(100, score));

  let status: HouseholdTrustResult["status"];
  if (clamped >= TRUST_STATUS_THRESHOLDS.upToDate) {
    status = "up_to_date";
  } else if (clamped >= TRUST_STATUS_THRESHOLDS.needsCheck) {
    status = "needs_check";
  } else {
    status = "uncertain";
  }

  return { score: clamped, status };
}

/** Pick the most urgent trust state from a list (used for household summary). */
export function worstTrustState(states: TrustState[]): TrustState {
  const order: TrustState[] = ["stale", "decaying", "unverified", "trusted"];
  for (const s of order) {
    if (states.includes(s)) return s;
  }
  return "unverified";
}
