import type { StoredArtifactRecord } from "../types/storage";
import { storedArtifactStrength } from "./artifactStore";

// Rescan-merge (ADR-006 open follow-up): leveling an artifact changes its store
// signature (level + substat values), so re-scanning a leveled piece creates a
// duplicate record. This collapses those duplicates using a level-independent
// identity: set + slot + main stat + the SET OF SUBSTAT NAMES (values and level
// excluded). Substat names do not change with leveling, so two scans of the same
// 5-star piece at different levels share an identity and merge; two genuinely
// different pieces with an identical substat lineup can still be merged, which is
// an accepted, low-stakes risk for a triage helper (hence an explicit
// reconciliation pass, not a change to the per-save signature).

export function substatName(substat: string): string {
  const plusIndex = substat.indexOf("+");
  return (plusIndex >= 0 ? substat.slice(0, plusIndex) : substat).trim();
}

export function mergeIdentity(record: StoredArtifactRecord): string {
  const substatNames = record.substats.map(substatName).filter(Boolean).sort().join(",");
  return [record.setName, record.slot, record.mainStat, substatNames].join("::");
}

// The more-progressed / stronger record wins: higher level first, then strength.
function preferred(a: StoredArtifactRecord, b: StoredArtifactRecord): StoredArtifactRecord {
  const levelA = a.level ?? 0;
  const levelB = b.level ?? 0;
  if (levelA !== levelB) return levelA > levelB ? a : b;
  return storedArtifactStrength(a) >= storedArtifactStrength(b) ? a : b;
}

function minDate(a: string | undefined, b: string | undefined): string | undefined {
  if (!a) return b;
  if (!b) return a;
  return a <= b ? a : b;
}

function maxDate(a: string | undefined, b: string | undefined): string | undefined {
  if (!a) return b;
  if (!b) return a;
  return a >= b ? a : b;
}

function mergePair(winner: StoredArtifactRecord, other: StoredArtifactRecord): StoredArtifactRecord {
  return {
    ...winner,
    // The winner needs review only if it did on its own; a confident higher-level
    // scan should clear a stale low-confidence duplicate.
    needsReview: winner.needsReview,
    timesSeen: (winner.timesSeen ?? 1) + (other.timesSeen ?? 1),
    firstSeenAt: minDate(winner.firstSeenAt, other.firstSeenAt),
    lastSeenAt: maxDate(winner.lastSeenAt, other.lastSeenAt),
    // Keep an equipped character if either scan detected one.
    equipped:
      winner.equipped && !/not detected/i.test(winner.equipped)
        ? winner.equipped
        : other.equipped,
  };
}

export interface MergeResult {
  merged: StoredArtifactRecord[];
  collapsed: number;
}

export function mergeRescannedArtifacts(records: readonly StoredArtifactRecord[]): MergeResult {
  const byIdentity = new Map<string, StoredArtifactRecord>();
  let collapsed = 0;

  for (const record of records) {
    const identity = mergeIdentity(record);
    const existing = byIdentity.get(identity);
    if (!existing) {
      byIdentity.set(identity, record);
      continue;
    }
    const winner = preferred(existing, record);
    const loser = winner === existing ? record : existing;
    byIdentity.set(identity, mergePair(winner, loser));
    collapsed++;
  }

  return { merged: [...byIdentity.values()], collapsed };
}
