import { hashId } from "./artifactStore.js";
import type { ParsedArtifactCandidate } from "./artifactOcrParser.js";
import type {
  ArtifactValueStatus,
  ScanResultFieldConfidence,
  ScanResultIkMatch,
  ScanResultExtractionStatus,
  ScanResultCategory,
  StoredScanResultEntry,
} from "../types/storage.js";

export interface ScanResultEntryInput {
  runId: string;
  sequence: number;
  page?: number;
  row?: number;
  col?: number;
  category?: ScanResultCategory;
  source: string;
  imagePath: string;
  parsed: ParsedArtifactCandidate | null;
  needsReview: boolean;
  confidence: number;
  capturedAt?: string;
  artifactRecordId?: string;
  persistedArtifact?: boolean;
  notes?: string[];
  error?: string;
  locked?: boolean;
  ikMatch?: ScanResultIkMatch;
}

export function deriveScanResultExtractionStatus(input: {
  parsed: boolean;
  needsReview: boolean;
  error?: string;
}): ScanResultExtractionStatus {
  if (input.error === "Card crop image missing.") return "missing_crop";
  if (input.error) return input.parsed ? "review" : "error";
  if (!input.parsed) return "parse_error";
  if (input.needsReview) return "review";
  return "parsed";
}

export function deriveArtifactValueStatus(extractionStatus: ScanResultExtractionStatus): ArtifactValueStatus {
  return extractionStatus === "parsed" ? "deferred" : "review";
}

export function createStoredScanResultEntry(input: ScanResultEntryInput): StoredScanResultEntry {
  const category = input.category ?? "artifact";
  const extractionStatus = deriveScanResultExtractionStatus({
    parsed: Boolean(input.parsed),
    needsReview: input.needsReview,
    error: input.error,
  });
  const id = hashId([
    input.runId,
    input.sequence,
    category,
    input.imagePath,
    input.parsed?.name ?? "",
    input.parsed?.slot ?? "",
    input.error ?? "",
  ].join("::"));

  return {
    id,
    runId: input.runId,
    sequence: input.sequence,
    page: input.page,
    row: input.row,
    col: input.col,
    category,
    source: input.source,
    imagePath: input.imagePath,
    capturedAt: input.capturedAt ?? new Date(0).toISOString(),
    extractionStatus,
    extractionConfidence: Math.max(0, Math.round(input.confidence || 0)),
    needsReview: extractionStatus !== "parsed",
    valueStatus: deriveArtifactValueStatus(extractionStatus),
    valueScore: null,
    artifact: input.parsed
      ? {
          name: input.parsed.name,
          slot: input.parsed.slot,
          level: input.parsed.level,
          setName: input.parsed.setName,
          mainStat: input.parsed.mainStat,
          mainValue: input.parsed.mainValue,
          substats: [...input.parsed.substats],
          equipped: input.parsed.equipped,
          locked: input.locked,
        }
      : undefined,
    ikMatch: input.ikMatch,
    fieldConfidences: input.parsed ? parsedFieldConfidences(input.parsed) : undefined,
    artifactRecordId: input.artifactRecordId,
    persistedArtifact: Boolean(input.persistedArtifact),
    notes: [...(input.notes ?? input.parsed?.notes ?? [])],
    error: input.error,
  };
}

function parsedFieldConfidences(parsed: ParsedArtifactCandidate): ScanResultFieldConfidence[] {
  return [
    fieldConfidence("name", "Name", parsed.fields.name),
    fieldConfidence("slot", "Slot", parsed.fields.slot),
    fieldConfidence("level", "Level", parsed.fields.level),
    fieldConfidence("mainStat", "Main stat", parsed.fields.mainStat),
    fieldConfidence("mainValue", "Main value", parsed.fields.mainValue),
    fieldConfidence("setName", "Set", parsed.fields.setName),
    fieldConfidence("equipped", "Equipped", parsed.fields.equipped),
    fieldConfidence("substats", "Substats", parsed.fields.substats),
  ].filter((entry): entry is ScanResultFieldConfidence => Boolean(entry));
}

function fieldConfidence(
  key: string,
  label: string,
  parsedField: ParsedArtifactCandidate["fields"][keyof ParsedArtifactCandidate["fields"]] | undefined,
): ScanResultFieldConfidence | null {
  if (!parsedField) return null;
  return {
    key,
    label,
    value: parsedField.value,
    confidence: Math.max(0, Math.round(parsedField.confidence || 0)),
    source: parsedField.source,
  };
}
