import { hashId } from "./artifactStore.js";
import type { StoredArtifactRecord, StoredScanResultEntry } from "../types/storage.js";

export type ScanResultPromotionStatus =
  | "ready"
  | "already_stored"
  | "persisted"
  | "review"
  | "blocked";

export interface ScanResultPromotionDecision {
  resultId: string;
  sequence: number;
  status: ScanResultPromotionStatus;
  label: string;
  className: "ok" | "warn" | "muted";
  canPersist: boolean;
  artifactRecordId?: string;
  reasons: string[];
}

export interface ScanResultPromotionSummary {
  total: number;
  ready: number;
  alreadyStored: number;
  persisted: number;
  review: number;
  blocked: number;
  title: string;
  detail: string;
  className: "ok" | "warn" | "muted";
  decisions: ScanResultPromotionDecision[];
}

export function buildScanResultPromotionSummary(
  nativeResults: readonly StoredScanResultEntry[] = [],
  storedArtifacts: readonly StoredArtifactRecord[] = [],
): ScanResultPromotionSummary {
  const storedIds = new Set(storedArtifacts.map((artifact) => artifact.id));
  const decisions = nativeResults.map((entry) => classifyScanResultPromotion(entry, storedIds));
  const ready = decisions.filter((decision) => decision.status === "ready").length;
  const alreadyStored = decisions.filter((decision) => decision.status === "already_stored").length;
  const persisted = decisions.filter((decision) => decision.status === "persisted").length;
  const review = decisions.filter((decision) => decision.status === "review").length;
  const blocked = decisions.filter((decision) => decision.status === "blocked").length;
  const className = ready > 0 ? "ok" : review + blocked > 0 ? "warn" : "muted";

  return {
    total: nativeResults.length,
    ready,
    alreadyStored,
    persisted,
    review,
    blocked,
    title: "Native Promotion",
    detail: promotionSummaryDetail({ total: nativeResults.length, ready, alreadyStored, persisted, review, blocked }),
    className,
    decisions,
  };
}

export function classifyScanResultPromotion(
  entry: StoredScanResultEntry,
  storedIds: ReadonlySet<string> = new Set(),
): ScanResultPromotionDecision {
  const artifactRecordId = entry.artifactRecordId || deriveStoreIdFromScanResult(entry);
  const base = {
    resultId: entry.id,
    sequence: entry.sequence,
    artifactRecordId,
  };

  if (entry.persistedArtifact || (entry.artifactRecordId && storedIds.has(entry.artifactRecordId))) {
    return {
      ...base,
      status: "persisted",
      label: "Persistiert",
      className: "muted",
      canPersist: false,
      reasons: ["Native result is already persisted in the artifact store."],
    };
  }

  const blockingReasons = scanResultBlockingReasons(entry);
  if (blockingReasons.length > 0) {
    const hasParsedArtifact = Boolean(entry.artifact);
    return {
      ...base,
      status: hasParsedArtifact ? "review" : "blocked",
      label: hasParsedArtifact ? "Review" : "Blockiert",
      className: "warn",
      canPersist: false,
      reasons: blockingReasons,
    };
  }

  if (artifactRecordId && storedIds.has(artifactRecordId)) {
    return {
      ...base,
      status: "already_stored",
    label: "Schon im Store",
      className: "muted",
      canPersist: false,
      reasons: ["Same artifact store identity already exists."],
    };
  }

  return {
    ...base,
    status: "ready",
    label: "Speicherbar",
    className: "ok",
    canPersist: true,
    reasons: ["Parsed, IK-matched, and complete enough for explicit promotion."],
  };
}

export function deriveStoreIdFromScanResult(entry: StoredScanResultEntry) {
  if (entry.category !== "artifact") return undefined;
  const artifact = entry.artifact;
  if (!artifact) return undefined;
  return hashId([
    artifact.name,
    artifact.slot,
    artifact.level,
    artifact.mainStat,
    artifact.mainValue,
    artifact.setName,
    artifact.substats.join("|"),
  ].join("::"));
}

export function scanResultToStoredArtifact(entry: StoredScanResultEntry): StoredArtifactRecord | null {
  const artifactRecordId = deriveStoreIdFromScanResult(entry);
  if (!artifactRecordId || !entry.artifact) return null;
  return {
    id: artifactRecordId,
    name: entry.artifact.name,
    slot: entry.artifact.slot,
    level: entry.artifact.level,
    setName: entry.artifact.setName,
    mainStat: entry.artifact.mainStat,
    mainValue: entry.artifact.mainValue,
    substats: [...entry.artifact.substats],
    equipped: entry.artifact.equipped,
    confidence: entry.extractionConfidence,
    needsReview: false,
    locked: entry.artifact.locked,
    source: "native-ik-scan",
  };
}

function scanResultBlockingReasons(entry: StoredScanResultEntry) {
  const reasons: string[] = [];
  if (entry.category !== "artifact") reasons.push("Only artifact scan results can be promoted into the artifact store.");
  if (!entry.artifact) reasons.push("No parsed artifact identity is available.");
  if (entry.extractionStatus !== "parsed" || entry.needsReview) {
    reasons.push(`Extraction status is ${entry.extractionStatus}.`);
  }
  if (entry.error) reasons.push(entry.error);

  const artifact = entry.artifact;
  if (artifact) {
    if (artifact.name === "Unknown artifact") reasons.push("Artifact name is unknown.");
    if (artifact.slot === "Unknown slot") reasons.push("Artifact slot is unknown.");
    if (artifact.setName === "Unknown set") reasons.push("Artifact set is unknown.");
    if (artifact.mainStat === "Unknown main stat") reasons.push("Main stat is unknown.");
    if (artifact.mainValue === "?") reasons.push("Main stat value is missing.");
    if (artifact.substats.length === 0) reasons.push("No substats were parsed.");
  }

  if (!entry.ikMatch) {
    reasons.push("IK inventorylist match is missing.");
  } else if (!entry.ikMatch.matched) {
    reasons.push("IK inventorylist match has a set, piece, or slot conflict.");
  }

  const lowConfidenceFields = (entry.fieldConfidences ?? [])
    .filter((field) => field.confidence < 70)
    .map((field) => field.label);
  if (lowConfidenceFields.length > 0) {
    reasons.push(`Low field confidence: ${lowConfidenceFields.join(", ")}.`);
  }

  return [...new Set(reasons)];
}

function promotionSummaryDetail(input: {
  total: number;
  ready: number;
  alreadyStored: number;
  persisted: number;
  review: number;
  blocked: number;
}) {
  if (input.total === 0) return "Keine nativen Scan-Ergebnisse geladen.";
  const parts = [
    `${input.ready} speicherbar`,
    `${input.alreadyStored + input.persisted} im Store`,
    `${input.review} Review`,
    `${input.blocked} blockiert`,
  ];
  return parts.join(" - ");
}
