import { conflict, notFound } from "./errors.mjs";

const DEFAULT_CASES = Object.freeze([
  Object.freeze({
    id: "DENIAL-001",
    tenantId: "aster-health",
    revision: 7,
    payer: "NorthLake",
    denialCode: "CO-50",
    originalClaim: Object.freeze({ modifier25Present: true }),
    encounterEvidence: Object.freeze({ separatelyDocumentedSameDayEvaluation: true }),
    recommendations: Object.freeze([]),
  }),
  Object.freeze({
    id: "DENIAL-002",
    tenantId: "aster-health",
    revision: 3,
    payer: "Summit",
    denialCode: "CO-16",
    originalClaim: Object.freeze({ modifier25Present: false }),
    encounterEvidence: Object.freeze({ separatelyDocumentedSameDayEvaluation: false }),
    recommendations: Object.freeze([]),
  }),
]);

function copy(value) {
  return structuredClone(value);
}

export class SimulatedClaimsSystem {
  #cases = new Map();
  #operations = new Map();
  #operationSequence = 0;

  constructor(seedCases = DEFAULT_CASES) {
    for (const claimCase of seedCases) {
      this.#cases.set(`${claimCase.tenantId}:${claimCase.id}`, copy(claimCase));
    }
  }

  getCase(tenantId, caseId) {
    const claimCase = this.#cases.get(`${tenantId}:${caseId}`);
    if (!claimCase) {
      throw notFound("Claims case");
    }
    return copy(claimCase);
  }

  writeRecommendation({ tenantId, caseId, expectedRevision, recommendation }) {
    const key = `${tenantId}:${caseId}`;
    const claimCase = this.#cases.get(key);
    if (!claimCase) {
      throw notFound("Claims case");
    }
    if (claimCase.revision !== expectedRevision) {
      throw conflict(
        "stale_case_revision",
        "The case changed after it was read; refresh before retrying.",
        { expectedRevision, currentRevision: claimCase.revision },
      );
    }

    const operationId = `op-${String(++this.#operationSequence).padStart(4, "0")}`;
    const storedRecommendation = {
      ...copy(recommendation),
      operationId,
      recordedAt: new Date().toISOString(),
    };
    claimCase.recommendations.push(storedRecommendation);
    claimCase.revision += 1;

    const operation = {
      operationId,
      tenantId,
      caseId,
      effect: "recommendation_recorded",
      candidateId: storedRecommendation.candidateId,
      candidateDigest: storedRecommendation.candidateDigest,
      resultingCaseRevision: claimCase.revision,
      recordedAt: storedRecommendation.recordedAt,
    };
    this.#operations.set(`${tenantId}:${operationId}`, operation);
    return copy(operation);
  }

  getOperation(tenantId, operationId) {
    const operation = this.#operations.get(`${tenantId}:${operationId}`);
    if (!operation) {
      throw notFound("Operation");
    }
    return copy(operation);
  }

  recommendationCount(tenantId, caseId) {
    return this.getCase(tenantId, caseId).recommendations.length;
  }
}

export { DEFAULT_CASES };
