import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'

const root = resolve(new URL('..', import.meta.url).pathname)
const load = (path) => readFile(resolve(root, path), 'utf8').then(JSON.parse)
const [workflow, inventory, exactPlan] = await Promise.all([
  load('config/freecad-gui-workflow-plan.json'),
  load('config/freecad-gui-command-inventory.json'),
  load('config/freecad-web-exact-parity-plan.json'),
])

const fail = (message) => { throw new Error(`FreeCAD GUI workflow plan: ${message}`) }
const lockedCommit = '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d'
if (workflow.schemaVersion !== 1 || workflow.baseline?.freecadVersion !== '1.1.1' || workflow.baseline?.commit !== lockedCommit) fail('baseline mismatch.')
if (inventory.baseline?.commit !== lockedCommit || exactPlan.baseline?.freecadCommit !== lockedCommit) fail('input baseline mismatch.')

const family = workflow.family
if (!family?.id || !family.title || !family.workbench || !family.primaryCommand || !family.primaryExactTask || !family.selectionReason) fail('selected family metadata is incomplete.')
if (!Array.isArray(family.commandIds) || family.commandIds.length === 0 || !family.commandIds.includes(family.primaryCommand)) fail('selected command family is incomplete.')
if (!Array.isArray(family.relatedExactTasks) || family.relatedExactTasks.length === 0) fail('related exact tasks are missing.')

const exactTaskIds = new Set(exactPlan.programs.flatMap((program) => program.tasks.map((task) => task.id)))
for (const taskId of [family.primaryExactTask, ...family.relatedExactTasks]) if (!exactTaskIds.has(taskId)) fail(`selected family references unknown exact task ${taskId}.`)

const commandById = new Map(inventory.commands.map((command) => [command.id, command]))
for (const commandId of family.commandIds) if (!commandById.has(commandId)) fail(`selected command ${commandId} is absent from the runtime inventory.`)
const primary = commandById.get(family.primaryCommand)
const sensitivity = workflow.sensitivityEvidence
if (sensitivity?.source !== 'config/freecad-gui-command-inventory.json' || sensitivity.commandId !== family.primaryCommand) fail('sensitivity provenance is incomplete.')
if (sensitivity.documentSensitive !== primary.documentSensitive || sensitivity.selectionSensitive !== primary.selectionSensitive) fail('selected sensitivity flags do not match the runtime inventory.')
for (const caseName of ['noDocument', 'documentNoSelection', 'selectedPartBox']) {
  if (JSON.stringify(sensitivity.cases?.[caseName]) !== JSON.stringify(primary.cases?.[caseName]?.states)) fail(`${caseName} sensitivity evidence is stale.`)
}

const stateNames = ['success', 'disabled', 'failure', 'cancel', 'recovery']
for (const stateName of stateNames) {
  const recipe = workflow.stateRecipes?.[stateName]
  if (!recipe?.setup || !recipe.action || !recipe.expected) fail(`${stateName} workflow recipe is incomplete.`)
}

const expectedTaskIds = Array.from({ length: 7 }, (_, index) => `ORA-GUI-WF-${String(index).padStart(3, '0')}`)
if (!Array.isArray(workflow.progress) || workflow.progress.map((entry) => entry.taskId).join(',') !== expectedTaskIds.join(',')) fail('workflow progress must contain ordered ORA-GUI-WF-000 through 006 tasks.')
const statuses = workflow.progress.map((entry) => entry.status)
const inProgressCount = statuses.filter((status) => status === 'in_progress').length
if (inProgressCount > 1 || statuses.some((status) => !['completed', 'in_progress', 'pending'].includes(status))) fail('workflow progress has invalid statuses.')
const inProgressIndex = statuses.indexOf('in_progress')
if (inProgressCount === 0 && statuses.some((status) => status !== 'completed')) fail('workflow progress without an in-progress task must be fully completed.')
if (inProgressCount === 1 && (statuses.slice(0, inProgressIndex).some((status) => status !== 'completed') || statuses.slice(inProgressIndex + 1).some((status) => status !== 'pending'))) fail('workflow progress is not a contiguous serial queue.')
for (const [index, entry] of workflow.progress.entries()) {
  if (!Array.isArray(entry.evidence)) fail(`${entry.taskId} evidence must be an array.`)
  if (index < inProgressIndex && entry.evidence.length === 0) fail(`${entry.taskId} is completed without evidence.`)
}

console.log(JSON.stringify({
  status: 'freecad-gui-workflow-plan-pass',
  family: family.id,
  primaryCommand: family.primaryCommand,
  primaryExactTask: family.primaryExactTask,
  completed: statuses.filter((status) => status === 'completed').length,
  inProgress: inProgressIndex >= 0 ? workflow.progress[inProgressIndex].taskId : null,
  pending: statuses.filter((status) => status === 'pending').length,
}, null, 2))
