import fs from 'node:fs'
import crypto from 'node:crypto'

const read = p => JSON.parse(fs.readFileSync(p, 'utf8'))
const scenarioPath = 'contracts/testing/kbx.test-scenarios.json'
const fixturePath = 'contracts/testing/kbx.test-fixtures.json'
const scenarios = read(scenarioPath)
const fixtures = read(fixturePath)
const sha = p => crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex')
const scenarioSha = sha(scenarioPath)
const fixtureSha = sha(fixturePath)

const manifest = {
  schemaVersion: scenarios.schemaVersion,
  contractVersion: scenarios.contractVersion,
  sourceSha256: scenarioSha,
  fixtureVersion: fixtures.fixtureVersion,
  fixtureSourceSha256: fixtureSha,
  fixedReferenceClock: scenarios.principles.fixedReferenceClock,
  scenarios: scenarios.scenarios.map(s => ({
    id: s.id,
    title: s.title,
    screenId: s.screenId,
    kind: s.kind,
    tags: s.tags,
    fixtureSets: s.fixtureSets,
    requiredPermissions: s.requiredPermissions,
    apiOperations: s.apiOperations,
    isolation: s.isolation,
    assertionCount: s.assertions.length,
    evidence: s.evidence,
  })),
}
fs.writeFileSync('generated/test-scenario-manifest.json', JSON.stringify(manifest, null, 2) + '\n')

const fixtureManifest = {
  schemaVersion: fixtures.schemaVersion,
  fixtureVersion: fixtures.fixtureVersion,
  sourceSha256: fixtureSha,
  syntheticOnly: fixtures.syntheticOnly,
  fixedReferenceClock: fixtures.fixedReferenceClock,
  testTenant: fixtures.testTenant,
  fixtureSets: fixtures.fixtureSets,
  refCount: Object.keys(fixtures.refs ?? {}).length,
}
fs.writeFileSync('generated/test-fixture-manifest.json', JSON.stringify(fixtureManifest, null, 2) + '\n')

const scenarioCatalog = Object.fromEntries(scenarios.scenarios.map(s => [s.id, s]))
const fixtureSetCatalog = Object.fromEntries(fixtures.fixtureSets.map(s => [s.id, s]))
const ts = `// generated from KBX test contracts; do not edit.\n` +
  `// Scenario SHA256: ${scenarioSha}\n// Fixture SHA256: ${fixtureSha}\n\n` +
  `import type { KbxTestScenarioDefinition, KbxTestFixtureSetDefinition } from '../testing'\n\n` +
  `export const kbxTestScenarioContractVersion = ${JSON.stringify(scenarios.contractVersion)} as const\n` +
  `export const kbxTestFixtureVersion = ${JSON.stringify(fixtures.fixtureVersion)} as const\n` +
  `export const kbxTestReferenceClock = ${JSON.stringify(scenarios.principles.fixedReferenceClock)} as const\n\n` +
  `export const kbxTestScenarioCatalog = ${JSON.stringify(scenarioCatalog, null, 2)} as const satisfies Record<string, KbxTestScenarioDefinition>\n\n` +
  `export const kbxTestFixtureSetCatalog = ${JSON.stringify(fixtureSetCatalog, null, 2)} as const satisfies Record<string, KbxTestFixtureSetDefinition>\n` +
  `export const kbxTestFixtureRefs = ${JSON.stringify(fixtures.refs, null, 2)} as const\n`
fs.writeFileSync('packages/kbx-contracts/src/generated/testScenarioCatalog.ts', ts)

const csString = s => `"${String(s).replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"`
const csList = a => `new[] { ${(a ?? []).map(csString).join(', ')} }`
const rows = scenarios.scenarios.map(s =>
  `        new(${csString(s.id)}, ${csString(s.title)}, ${csString(s.screenId)}, ${csString(s.kind)}, ${csList(s.tags)}, ${csList(s.fixtureSets)}, ${csList(s.requiredPermissions)}, ${csList(s.apiOperations)}, ${csString(s.isolation)})`
).join(',\n')
const cs = `// GENERATED. DO NOT EDIT.\n// Scenario SHA256: ${scenarioSha}\n// Fixture SHA256: ${fixtureSha}\nnamespace Shared.Testing.Generated;\n\npublic sealed record KbxTestScenarioContract(\n    string Id, string Title, string ScreenId, string Kind,\n    IReadOnlyList<string> Tags, IReadOnlyList<string> FixtureSets,\n    IReadOnlyList<string> RequiredPermissions, IReadOnlyList<string> ApiOperations,\n    string Isolation);\n\npublic static class KbxTestScenarioCatalog\n{\n    public const string ContractVersion = ${csString(scenarios.contractVersion)};\n    public const string FixtureVersion = ${csString(fixtures.fixtureVersion)};\n    public const string ReferenceClock = ${csString(scenarios.principles.fixedReferenceClock)};\n    public static IReadOnlyList<KbxTestScenarioContract> All { get; } = new KbxTestScenarioContract[]\n    {\n${rows}\n    };\n}\n`
fs.writeFileSync('backend/Shared/Testing/Generated/KbxTestScenarioCatalog.g.cs', cs)

console.log(`test contracts generated: scenarios=${scenarios.scenarios.length}, fixtureSets=${fixtures.fixtureSets.length}, refs=${Object.keys(fixtures.refs ?? {}).length}`)
