/**
 * DocCenter Path Registry — Single Source of Truth
 *
 * ALL DocCenter path references across the codebase should derive from here.
 * After changing values: run `npm run sync-doc-paths` to update
 * hardcoded occurrences in workflow JSONs and seed workflows.
 *
 * Structure: { alias: { path, docId, desc } }
 *   - path: DocCenter path number (stable identifier used in workflow JSONs)
 *   - docId: DocCenter document ID (may differ from path; resolved at runtime if null)
 *   - desc: Human-readable description (synced to workflow registry.docs)
 */

// ─── DocCenter API ──────────────────────────────────────────────
/** Cloud DocCenter API base URL */
export const DOCCENTER_API_URL = 'https://v4pre.visuallogic.ai/api/12027022';

/** Local DocCenter API base URL (fallback when available) */
export const DOCCENTER_LOCAL_URL = 'http://localhost:9300';

/** Stable doc reference prefix exposed in UI */
export const DOC_REF_PREFIX = 'vl://doc/';

/** Embedded DocCenter viewer route used by VLCode */
export const DOCCENTER_VIEW_PATH = '/doc-center.html';

// ─── Core Specs (paths 1-9, RESERVED) ──────────────────────────
export const CORE_DOCS = {
  vlSyntax:       { path: 1,   docId: 1,    desc: 'VL Syntax 3.7' },
  theme:          { path: 2,   docId: 4,    desc: 'THEME 6.6 Enterprise' },
  metaSpec:       { path: 4,   docId: 16,   desc: 'VL Metadata Spec 3.1' },
  workflowSpec:   { path: 3,   docId: 2,    desc: 'Workflow Spec 3.19' },
  componentFactory: { path: 6, docId: 15,   desc: 'VL Component Factory' },
  docCenterAPI:   { path: 7,   docId: 95,   desc: 'DocCenter API' },
  workspaceAPI:   { path: 8,   docId: 94,   desc: 'Workspace Doc API' },
  charter:        { path: 9,   docId: null, desc: 'VLClaw Community Charter' },
};

export const CORE_DOC_ALIASES = ['vlSyntax', 'theme', 'metaSpec', 'workflowSpec'];
export const LOCKED_DOC_ALIASES = ['metaSpec', 'workflowSpec'];
export const EDITABLE_DOC_ALIASES = [
  'vlSyntax',
  'theme',
  'workflow3File',
  'workflow6File',
  'workflow9File',
  'workflowMetaDirect',
  'workflowAddPage',
  'workflowAddService',
  'workflowThemeCustomize',
  'workflowIncrementalUpdate',
  'workflowCompileFix',
];

// ─── Platform APIs (paths 10-29, RESTRICTED) ────────────────────
export const PLATFORM_DOCS = {
  docIndex:       { path: 10,  docId: 97,   desc: 'DocCenter Index' },
  dbGenAgent:     { path: 20,  docId: null, desc: 'Agent-200-DB: Database schema generation' },
  platformAPIs:   { path: 22,  docId: null, desc: 'Platform APIs v1.0' },
};

// ─── 3-File Workflow Agents (paths 30-39) ───────────────────────
export const THREE_FILE_DOCS = {
  agent3_100_PRD:       { path: 31, docId: null, desc: 'Agent-100-PRD-Prompt' },
  agent3_200_DB:        { path: 32, docId: null, desc: 'Agent-200-DB-Prompt' },
  agent3_300_ServiceMap: { path: 33, docId: null, desc: 'Agent-300-ServiceMap-Prompt' },
  agent3_400_UIMap:     { path: 34, docId: null, desc: 'Agent-400-UIMap-Prompt' },
  agent3_500_Component: { path: 35, docId: null, desc: 'Agent-500-Component-Prompt' },
  agent3_600_Service:   { path: 36, docId: null, desc: 'Agent-600-ServiceDomain-Prompt' },
  agent3_700_Section:   { path: 37, docId: null, desc: 'Agent-700-Section-Prompt' },
  agent3_800_App:       { path: 38, docId: null, desc: 'Agent-800-AppEntry-Prompt' },
};

// ─── Adjustment Workflow Agents (paths 50-59) ───────────────────
export const ADJUST_DOCS = {
  incrUpdateMeta:  { path: 50, docId: null, desc: 'Legacy Incremental-Update prompt (path currently unavailable in DocCenter)' },
  incrRegen:       { path: 52, docId: null, desc: 'Legacy Incremental-Regen prompt (path currently unavailable in DocCenter)' },
};

// ─── 6-File Workflow Agents (paths 60-79) ───────────────────────
export const SIX_FILE_DOCS = {
  agent6_100_Blueprint:   { path: 61, docId: null, desc: 'Agent-100-Blueprint-Prompt' },
  agent6_200_DataSchema:  { path: 62, docId: null, desc: 'Agent-200-DataSchema-Prompt' },
  agent6_250_LayoutPlan:  { path: 63, docId: null, desc: 'Agent-250-LayoutPlan-Prompt' },
  agent6_300_Contract:    { path: 64, docId: null, desc: 'Agent-300-ContractSheet-Prompt' },
  agent6_400_State:       { path: 65, docId: null, desc: 'Agent-400-StateBehavior-Prompt' },
  agent6_450_Manifest:    { path: 66, docId: null, desc: 'Agent-450-FileManifest-Prompt' },
  agent6_610_VDB:         { path: 67, docId: null, desc: 'Agent-610-VDB-Prompt' },
  agent6_620_VTH:         { path: 68, docId: null, desc: 'Agent-620-VTH-Prompt' },
  agent6_630_VS:          { path: 69, docId: null, desc: 'Agent-630-VS-Prompt' },
  agent6_640_CP:          { path: 70, docId: null, desc: 'Agent-640-CP-Prompt' },
  agent6_650_SC:          { path: 71, docId: null, desc: 'Agent-650-SC-Prompt' },
  agent6_660_VX:          { path: 72, docId: null, desc: 'Agent-660-VX-Prompt' },
  aux6FileSpec:           { path: 79, docId: null, desc: 'VL-Aux-6File-Spec' },
};

// ─── 9-File Workflow Agents (paths 90-109) ──────────────────────
export const NINE_FILE_DOCS = {
  agent9_100_IntentSpec:    { path: 91,  docId: null, desc: 'Agent-100-IntentSpec-Prompt' },
  agent9_200_DomainSchema:  { path: 92,  docId: null, desc: 'Agent-200-DomainSchema-Prompt' },
  agent9_300_ServiceContract: { path: 93, docId: null, desc: 'Agent-300-ServiceContractMap-Prompt' },
  agent9_400_UIContract:    { path: 94,  docId: null, desc: 'Agent-400-UIContractMap-Prompt' },
  agent9_500_ModuleManifest: { path: 95, docId: null, desc: 'Agent-500-ModuleManifest-Prompt' },
  agent9_600_DepGraph:      { path: 96,  docId: null, desc: 'Agent-600-DependencyGraph-Prompt' },
  agent9_700_QualityGate:   { path: 97,  docId: null, desc: 'Agent-700-QualityGateSpec-Prompt' },
  agent9_800_ExecPlan:      { path: 98,  docId: null, desc: 'Agent-800-ExecutionPlan-Prompt' },
  agent9_900_RepairSpecs:   { path: 99,  docId: null, desc: 'Agent-900-RepairSpecs-Prompt' },
  aux9FileSpec:             { path: 109, docId: null, desc: 'VL-Aux-9File-Spec' },
};

// ─── MetaDirect Workflow Agents (paths 100-111) ─────────────────
export const META_DIRECT_DOCS = {
  agentMD_GenDB:       { path: 100, docId: null, desc: 'Agent-GenDatabase-Prompt' },
  agentMD_GenTheme:    { path: 101, docId: null, desc: 'Agent-GenTheme-Prompt' },
  agentMD_GenService:  { path: 102, docId: null, desc: 'Agent-GenServiceDomain-Prompt' },
  agentMD_GenComponent: { path: 103, docId: null, desc: 'Agent-GenComponent-Prompt' },
  agentMD_GenSection:  { path: 104, docId: null, desc: 'Agent-GenSection-Prompt' },
  agentMD_GenApp:      { path: 105, docId: null, desc: 'Agent-GenApp-Prompt' },
  agentMD_RepairPlan:  { path: 106, docId: null, desc: 'Agent-RepairPlan-Prompt' },
  agentMD_RepairFile:  { path: 107, docId: null, desc: 'Agent-RepairVLFile-Prompt' },
  agentMD_MetaDirect:  { path: 111, docId: null, desc: 'Agent-MetaDirect: Generate ProjectMeta directly from user request' },
};

// ─── Workflow Docs (paths 30/60/90/110+) ────────────────────────
export const WORKFLOW_DOCS = {
  workflow3File:          { path: 30,  docId: 8,  desc: 'VL_FullStack_CodeGen_3Files_v3.16' },
  workflow6File:          { path: 60,  docId: 34, desc: 'VL_FullStack_CodeGen_6Files_v3.16' },
  workflow9File:          { path: 90,  docId: 52, desc: 'VL_FullStack_CodeGen_9Files_v3.16' },
  workflowMetaDirect:     { path: 110, docId: 54, desc: 'VL_MetaDirect_CodeGen_v1' },
  workflowAddPage:        { path: 120, docId: 55, desc: 'VL_AddPage_Workflow_v1' },
  workflowAddService:     { path: 130, docId: 56, desc: 'VL_AddService_Workflow_v1' },
  workflowThemeCustomize: { path: 140, docId: 57, desc: 'VL_ThemeCustomize_Workflow_v1' },
  workflowIncrementalUpdate: { path: 141, docId: 117, desc: 'VL_IncrementalUpdate_Workflow_v1' },
  workflowCompileFix:     { path: 142, docId: 119, desc: 'VL_CompileFix_Workflow_v2' },
  workflowEngineAPI:      { path: 150, docId: 61, desc: 'VL-Workflow-Engine API Reference' },
};

// ─── Reports / Audits (paths 160+) ────────────────────────────
export const REPORT_DOCS = {
  workflowAudit20260314:  { path: 161, docId: 120, desc: 'VL-Code Workflow Audit Report 2026-03-14' },
};

// ─── Merged flat map: path → { alias, docId, desc } ────────────
const ALL_GROUPS = [
  CORE_DOCS, PLATFORM_DOCS, THREE_FILE_DOCS, ADJUST_DOCS,
  SIX_FILE_DOCS, NINE_FILE_DOCS, META_DIRECT_DOCS, WORKFLOW_DOCS, REPORT_DOCS,
];

/** Full registry: { alias → { path, docId, desc } } */
export const DOC_REGISTRY = {};
for (const group of ALL_GROUPS) {
  for (const [alias, entry] of Object.entries(group)) {
    DOC_REGISTRY[alias] = entry;
  }
}

/** Reverse lookup: path number → { alias, docId, desc } */
export const PATH_MAP = new Map();
for (const [alias, entry] of Object.entries(DOC_REGISTRY)) {
  PATH_MAP.set(entry.path, { alias, ...entry });
}

// ─── Helpers ────────────────────────────────────────────────────

/** Get path number by alias */
export function pathFor(alias) {
  return DOC_REGISTRY[alias]?.path ?? null;
}

export function normalizeDocId(value) {
  if (typeof value === 'number') {
    return Number.isInteger(value) && value > 0 ? value : null;
  }
  if (typeof value !== 'string') return null;
  const trimmed = value.trim();
  if (!trimmed) return null;

  if (/^\d+$/.test(trimmed)) {
    const n = Number.parseInt(trimmed, 10);
    return Number.isInteger(n) && n > 0 ? n : null;
  }

  if (trimmed.toLowerCase().startsWith(DOC_REF_PREFIX)) {
    return normalizeDocId(trimmed.slice(DOC_REF_PREFIX.length));
  }

  const inlineMatch = trimmed.match(/(?:^|[?&#])(?:docId|id|ref)=([^&#]+)/i);
  if (inlineMatch?.[1]) {
    try {
      return normalizeDocId(decodeURIComponent(inlineMatch[1]));
    } catch {
      return normalizeDocId(inlineMatch[1]);
    }
  }

  try {
    const parsed = new URL(trimmed, 'http://vl.local');
    const docId = parsed.searchParams.get('docId')
      || parsed.searchParams.get('id')
      || parsed.searchParams.get('ref');
    if (docId) return normalizeDocId(docId);
  } catch {
    return null;
  }

  const n = Number.parseInt(value, 10);
  return Number.isInteger(n) && n > 0 ? n : null;
}

export function docRefForId(docId) {
  const normalized = normalizeDocId(docId);
  return normalized ? `${DOC_REF_PREFIX}${normalized}` : '';
}

export function docHrefForId(docId, { origin = '' } = {}) {
  const normalized = normalizeDocId(docId);
  if (!normalized) return '';
  const prefix = origin ? String(origin).replace(/\/+$/, '') : '';
  return `${prefix}${DOCCENTER_VIEW_PATH}?docId=${normalized}`;
}

export function getDefaultCoreDocIds() {
  return Object.fromEntries(
    CORE_DOC_ALIASES.map((alias) => [alias, normalizeDocId(DOC_REGISTRY[alias]?.docId)])
  );
}

export function getDefaultDocIdOverrides() {
  return Object.fromEntries(
    EDITABLE_DOC_ALIASES.map((alias) => [alias, normalizeDocId(DOC_REGISTRY[alias]?.docId)])
  );
}

export function normalizeCoreDocIds(raw = {}, { includeDefaults = false } = {}) {
  const normalized = {};
  const defaults = includeDefaults ? getDefaultCoreDocIds() : {};
  for (const alias of CORE_DOC_ALIASES) {
    const value = normalizeDocId(raw?.[alias]);
    normalized[alias] = value ?? defaults[alias] ?? null;
  }
  return normalized;
}

export function normalizeDocIdOverrides(raw = {}, { includeDefaults = false } = {}) {
  const normalized = {};
  const defaults = includeDefaults ? getDefaultDocIdOverrides() : {};
  for (const alias of EDITABLE_DOC_ALIASES) {
    const value = normalizeDocId(raw?.[alias]);
    normalized[alias] = value ?? defaults[alias] ?? null;
  }
  return normalized;
}

export function aliasForPath(pathNum) {
  return PATH_MAP.get(Number(pathNum))?.alias ?? null;
}

export function docIdForPath(pathNum, overrides = null) {
  const alias = aliasForPath(pathNum);
  if (!alias) return null;
  return normalizeDocId(overrides?.[alias]) ?? normalizeDocId(DOC_REGISTRY[alias]?.docId);
}

export function coreDocIdForPath(pathNum, overrides = null) {
  const alias = aliasForPath(pathNum);
  if (!CORE_DOC_ALIASES.includes(alias)) return null;
  return normalizeDocId(overrides?.[alias]) ?? normalizeDocId(DOC_REGISTRY[alias]?.docId);
}

/** Get docId by alias (may be null — resolve at runtime) */
export function docIdFor(alias, overrides = null) {
  return normalizeDocId(overrides?.[alias]) ?? normalizeDocId(DOC_REGISTRY[alias]?.docId);
}

/** Get description by path number */
export function descForPath(pathNum) {
  return PATH_MAP.get(pathNum)?.desc ?? null;
}

/** Resolve a doc reference: accepts alias string or path number, returns path number */
export function resolveDocRef(ref) {
  if (typeof ref === 'number') return ref;
  if (typeof ref === 'string') {
    // Try alias first
    if (DOC_REGISTRY[ref]) return DOC_REGISTRY[ref].path;
    // Try as path number string
    const n = Number(ref);
    if (!isNaN(n)) return n;
  }
  return null;
}
