// ModuleCapabilityResolver (KAR-959/P2, Master-Prompt §32).
//
// The replacement-gate API: instead of a rigid template-classification check
// like
//
//   if (!isG60DetailQaf) { return emptyProductionData }
//
// or
//
//   showPriceCalculator = workbookType === 'G60_DETAIL'
//
// (gate-audit.md's 17 blocking gates, B1-B17), Master-Prompt §32 asks for
// capability-based logic:
//
//   if (capabilities.hasManufacturingDetail) { return extractAvailableManufacturingData(workbook) }
//   showPriceCalculator = availableFields.length > 0 || derivableFields.length > 0
//
// This module is that API surface, built on top of capability-detector.ts's
// WorkbookCapabilityMatrix. It does NOT touch any of the 17 cataloged gates
// itself (gate-audit.md §4's replacement order is explicitly P3/P4 —
// out of this PR's scope, task instruction point 3: "die Gates selbst werden
// erst in P3/P4 umgestellt — du lieferst die API, auf die sie umziehen").
//
// tdd-guard:skip — covered by __tests__/module-capability-resolver.test.ts.

import type { WorkbookCapabilityMatrix, ModuleCapability, QafModule, CapabilityStatus } from './types'

/** Statuses that represent SOME usable signal for a module — the "has
 * capability" gate-replacement predicate Master-Prompt §32's own example
 * uses ("availableFields.length > 0 || derivableFields.length > 0"). */
const USABLE_STATUSES: ReadonlySet<CapabilityStatus> = new Set<CapabilityStatus>(['AVAILABLE', 'PARTIAL', 'DERIVABLE'])

function findModule(matrix: WorkbookCapabilityMatrix, module: QafModule): ModuleCapability | undefined {
  return matrix.modules.find((m) => m.module === module)
}

/** The single finding for one module, or undefined when the matrix does not
 * cover that module at all (outside CAPABILITY_MODULES, e.g. G60/WAF/LAF/LEK
 * — see types.ts doc). */
export function moduleCapability(matrix: WorkbookCapabilityMatrix, module: QafModule): ModuleCapability | undefined {
  return findModule(matrix, module)
}

/** True only for CapabilityStatus AVAILABLE. */
export function isModuleAvailable(matrix: WorkbookCapabilityMatrix, module: QafModule): boolean {
  return findModule(matrix, module)?.status === 'AVAILABLE'
}

/** True for AVAILABLE, PARTIAL, or DERIVABLE — "there is SOMETHING usable
 * here", the direct Master-Prompt §32 gate-replacement predicate (its own
 * "availableFields.length > 0 || derivableFields.length > 0" example,
 * generalized to PARTIAL too — a partially-populated module is still more
 * useful to show than an unconditional placeholder). */
export function isModuleUsable(matrix: WorkbookCapabilityMatrix, module: QafModule): boolean {
  const finding = findModule(matrix, module)
  return finding !== undefined && USABLE_STATUSES.has(finding.status)
}

/** Every module currently AVAILABLE. */
export function availableModules(matrix: WorkbookCapabilityMatrix): QafModule[] {
  return matrix.modules.filter((m) => m.status === 'AVAILABLE').map((m) => m.module)
}

/** Every module with SOME usable signal (AVAILABLE | PARTIAL | DERIVABLE). */
export function usableModules(matrix: WorkbookCapabilityMatrix): QafModule[] {
  return matrix.modules.filter((m) => USABLE_STATUSES.has(m.status)).map((m) => m.module)
}

/**
 * The direct B15/B16/B17-shaped gate-replacement helper (gate-audit.md: UI
 * sections unconditionally hidden based on `comparison_mode`/template
 * classification instead of actual data availability) — true when ANY of
 * the given modules has usable data. A future P3/P4 migration of e.g.
 * qaf-comparison-detail.tsx's Sektion 6 "Produktionssicht" placeholder would
 * call `shouldShowSection(matrix, ['MANUFACTURING'])` instead of checking
 * `comparison_mode !== 'g60'`.
 */
export function shouldShowSection(matrix: WorkbookCapabilityMatrix, modules: readonly QafModule[]): boolean {
  return modules.some((m) => isModuleUsable(matrix, m))
}

/** Confidence-weighted summary — useful for a future UI badge ("this
 * comparison has N/8 modules available") without re-deriving it from
 * `matrix.modules` at every call site. */
export interface CapabilityCoverageSummary {
  totalModules: number
  available: number
  partial: number
  derivable: number
  missing: number
  parseFailed: number
}

export function summarizeCoverage(matrix: WorkbookCapabilityMatrix): CapabilityCoverageSummary {
  const counts: CapabilityCoverageSummary = {
    totalModules: matrix.modules.length,
    available: 0,
    partial: 0,
    derivable: 0,
    missing: 0,
    parseFailed: 0,
  }
  for (const m of matrix.modules) {
    if (m.status === 'AVAILABLE') counts.available++
    else if (m.status === 'PARTIAL') counts.partial++
    else if (m.status === 'DERIVABLE') counts.derivable++
    else if (m.status === 'MISSING') counts.missing++
    else if (m.status === 'PARSE_FAILED') counts.parseFailed++
  }
  return counts
}
