import type { CaptureModeDTO, CaptureStatus } from "@/lib/capture/types";

export type CaptureStatusInput = {
  captureMode: CaptureModeDTO;
  freshnessSlaHours: number;
  objectiveIndicator?: string | null;
  quantityQuality?: string | null;
  compliance?: string | null;
  compliancePct?: number | null;
  dueCommitment?: string | null;
  lastCapturedAt?: string | null;
  lastAutomationAt?: string | null;
  lastEvidenceAt?: string | null;
  latestRunStatus?: "queued" | "running" | "success" | "failed" | null;
  latestRunAt?: string | null;
  latestSuccessfulRunAt?: string | null;
  now?: Date;
};

function hasText(value: string | null | undefined): boolean {
  return Boolean(value?.trim());
}

function toDate(value: string | null | undefined): Date | null {
  if (!value) {
    return null;
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed;
}

function maxDate(values: Array<Date | null>): Date | null {
  const filtered = values.filter((value): value is Date => Boolean(value));
  if (filtered.length === 0) {
    return null;
  }

  return filtered.reduce((latest, current) => (current.getTime() > latest.getTime() ? current : latest));
}

export function computeCaptureProgress(input: Pick<CaptureStatusInput, "objectiveIndicator" | "quantityQuality" | "compliance" | "compliancePct" | "dueCommitment">) {
  const hasMeasurement = hasText(input.objectiveIndicator) || hasText(input.quantityQuality);
  const hasEvidenceSignal = hasText(input.quantityQuality);
  const hasScore = input.compliancePct !== null && input.compliancePct !== undefined ? true : hasText(input.compliance);
  const hasUpdate = hasText(input.dueCommitment);

  return {
    hasMeasurement,
    hasEvidenceSignal,
    hasScore,
    hasUpdate,
    isComplete: hasMeasurement && hasEvidenceSignal && hasScore && hasUpdate,
    isPartial: hasMeasurement || hasEvidenceSignal || hasScore || hasUpdate,
  };
}

function isFresh(referenceAt: Date | null, now: Date, freshnessSlaHours: number): boolean {
  if (!referenceAt) {
    return false;
  }

  const slaHours = Math.max(1, freshnessSlaHours);
  return now.getTime() - referenceAt.getTime() <= slaHours * 60 * 60 * 1000;
}

export function deriveCaptureStatus(input: CaptureStatusInput): CaptureStatus {
  const now = input.now ?? new Date();
  const progress = computeCaptureProgress(input);

  const lastCapturedAt = toDate(input.lastCapturedAt);
  const lastAutomationAt = toDate(input.lastAutomationAt);
  const lastEvidenceAt = toDate(input.lastEvidenceAt);
  const latestRunAt = toDate(input.latestRunAt);
  const latestSuccessfulRunAt = toDate(input.latestSuccessfulRunAt);

  const latestActivityAt = maxDate([lastCapturedAt, lastAutomationAt, lastEvidenceAt, latestSuccessfulRunAt]);
  const fresh = isFresh(latestActivityAt, now, input.freshnessSlaHours);

  const isAutoMode = input.captureMode === "auto" || input.captureMode === "hybrid";
  if (isAutoMode && input.latestRunStatus === "failed") {
    const successBeforeFailure = latestSuccessfulRunAt && latestRunAt && latestSuccessfulRunAt.getTime() > latestRunAt.getTime();
    if (!successBeforeFailure) {
      return "error";
    }
  }

  if (progress.isComplete) {
    return fresh ? "captured" : "stale";
  }

  if (isAutoMode && latestSuccessfulRunAt) {
    return fresh ? "captured" : "stale";
  }

  if (progress.isPartial || Boolean(lastEvidenceAt)) {
    return "in_progress";
  }

  if (latestActivityAt && !fresh) {
    return "stale";
  }

  return "pending";
}
