/**
 * Template-Spec v1 — Context Bridge Helpers
 *
 * Runtime functions: contextToPlaceholders, computeFlags, section relevance,
 * dot-path accessors. Split from contextBridge.ts for the 500 LOC hard cap.
 */

import type {
  TemplateContext,
  ProviderCtx,
  ComputedFlags,
  TOMCtx,
  DPACtx,
} from './contextBridge'

// =============================================================================
// Bridge: context → flat placeholder map
// =============================================================================

function str(v: unknown): string {
  if (v === null || v === undefined || v === '') return ''
  if (Array.isArray(v)) return v.join(', ')
  return String(v)
}

/** Compute compound address from PROVIDER fields */
function providerAddress(p: ProviderCtx): string {
  const parts = [p.ADDRESS_LINE, [p.POSTAL_CODE, p.CITY].filter(Boolean).join(' ')].filter(Boolean)
  return parts.join(', ')
}

/**
 * Maps a TemplateContext to a flat Record<string, string> of placeholder values.
 * Keys are the {{PLACEHOLDER}} strings used in templates.
 */
export function contextToPlaceholders(ctx: TemplateContext): Record<string, string> {
  const p = ctx.PROVIDER
  const c = ctx.CUSTOMER
  const s = ctx.SERVICE
  const l = ctx.LEGAL
  const prv = ctx.PRIVACY
  const sla = ctx.SLA
  const pay = ctx.PAYMENTS
  const sec = ctx.SECURITY
  const nda = ctx.NDA
  const con = ctx.CONSENT
  const h = ctx.HOSTING
  const f = ctx.FEATURES
  const tom = ctx.TOM
  const dpa = ctx.DPA

  const address = providerAddress(p)

  return {
    // --- PROVIDER ---
    '{{COMPANY_NAME}}':        str(p.LEGAL_NAME),
    '{{PROVIDER_NAME}}':       str(p.LEGAL_NAME),
    '{{DISCLOSING_PARTY}}':    str(p.LEGAL_NAME),   // NDA: provider is disclosing party
    '{{SERVICE_PROVIDER}}':    str(p.LEGAL_NAME),   // SLA
    '{{COMPANY_ADDRESS}}':     address,
    '{{PROVIDER_ADDRESS}}':    address,
    '{{CONTACT_EMAIL}}':       str(p.EMAIL),
    '{{PROVIDER_EMAIL}}':      str(p.EMAIL),
    '{{ABUSE_EMAIL}}':         str(p.EMAIL),        // AUP abuse contact
    '{{REPORT_EMAIL}}':        prv.CONTACT_EMAIL ? str(prv.CONTACT_EMAIL) : str(p.EMAIL), // community moderation

    // --- CUSTOMER ---
    '{{CUSTOMER_NAME}}':       str(c.LEGAL_NAME),
    '{{RECEIVING_PARTY}}':     str(c.LEGAL_NAME),   // NDA
    '{{CUSTOMER}}':            str(c.LEGAL_NAME),   // SLA

    // --- SERVICE ---
    '{{SERVICE_NAME}}':        str(s.NAME),
    '{{PLATFORM_NAME}}':       str(s.NAME),         // community / copyright
    '{{SERVICE_DESCRIPTION}}': str(s.DESCRIPTION),
    '{{SERVICE_MODEL}}':       str(s.MODEL),
    '{{SERVICE_TIER}}':        str(s.TIER),
    '{{DATA_LOCATION}}':       str(s.DATA_LOCATION),
    '{{EXPORT_FORMATS}}':      Array.isArray(s.EXPORT_FORMATS) ? s.EXPORT_FORMATS.join(', ') : '',
    '{{EXPORT_WINDOW_DAYS}}':  str(s.EXPORT_WINDOW_DAYS),
    '{{MIN_TERM_MONTHS}}':     str(s.MIN_TERM_MONTHS),
    '{{TERMINATION_NOTICE_DAYS}}': str(s.TERMINATION_NOTICE_DAYS),

    // --- LEGAL ---
    '{{GOVERNING_LAW}}':       str(l.GOVERNING_LAW),
    '{{JURISDICTION_CITY}}':   str(l.JURISDICTION_CITY),
    '{{VERSION_DATE}}':        str(l.VERSION_DATE),
    '{{EFFECTIVE_DATE}}':      str(l.EFFECTIVE_DATE),
    '{{START_DATE}}':          str(l.EFFECTIVE_DATE), // cloud contract start date

    // --- PRIVACY ---
    '{{PRIVACY_CONTACT_EMAIL}}': str(prv.CONTACT_EMAIL),
    '{{DPO_NAME}}':            str(prv.DPO_NAME),
    '{{DPO_EMAIL}}':           str(prv.DPO_EMAIL),
    '{{COPYRIGHT_CONTACT_NAME}}': str(prv.DPO_NAME), // copyright policy
    '{{COPYRIGHT_EMAIL}}':     str(prv.DPO_EMAIL),
    '{{PRIVACY_POLICY_URL}}':  str(prv.PRIVACY_POLICY_URL),
    '{{COOKIE_POLICY_URL}}':   str(prv.COOKIE_POLICY_URL),
    '{{ANALYTICS_RETENTION_MONTHS}}': str(prv.ANALYTICS_RETENTION_MONTHS),
    '{{DATA_TRANSFER_THIRD_COUNTRIES}}': str(prv.DATA_TRANSFER_THIRD_COUNTRIES),

    // --- SLA ---
    '{{AVAILABILITY_PERCENT}}':    str(sla.AVAILABILITY_PERCENT),
    '{{MAINTENANCE_NOTICE_HOURS}}': str(sla.MAINTENANCE_NOTICE_HOURS),
    '{{SUPPORT_EMAIL}}':           str(sla.SUPPORT_EMAIL),
    '{{SUPPORT_PHONE}}':           str(sla.SUPPORT_PHONE),
    '{{SUPPORT_HOURS}}':           str(sla.SUPPORT_HOURS),
    '{{RESPONSE_CRITICAL_H}}':     str(sla.RESPONSE_CRITICAL_H),
    '{{RESOLUTION_CRITICAL_H}}':   str(sla.RESOLUTION_CRITICAL_H),
    '{{RESPONSE_HIGH_H}}':         str(sla.RESPONSE_HIGH_H),
    '{{RESOLUTION_HIGH_H}}':       str(sla.RESOLUTION_HIGH_H),
    '{{RESPONSE_MEDIUM_H}}':       str(sla.RESPONSE_MEDIUM_H),
    '{{RESOLUTION_MEDIUM_H}}':     str(sla.RESOLUTION_MEDIUM_H),
    '{{RESPONSE_LOW_H}}':          str(sla.RESPONSE_LOW_H),

    // --- PAYMENTS ---
    '{{MONTHLY_FEE}}':         str(pay.MONTHLY_FEE_EUR),
    '{{PAYMENT_DUE_DAY}}':     str(pay.PAYMENT_DUE_DAY),
    '{{PAYMENT_METHOD}}':      str(pay.PAYMENT_METHOD),
    '{{PAYMENT_DAYS}}':        str(pay.PAYMENT_DAYS),

    // --- SECURITY ---
    '{{INCIDENT_NOTICE_HOURS}}':       str(sec.INCIDENT_NOTICE_HOURS),
    '{{LOG_RETENTION_DAYS}}':          str(sec.LOG_RETENTION_DAYS),
    '{{SECURITY_LOG_RETENTION_DAYS}}': str(sec.SECURITY_LOG_RETENTION_DAYS),

    // --- NDA ---
    '{{PURPOSE}}':             str(nda.PURPOSE),
    '{{DURATION_YEARS}}':      str(nda.DURATION_YEARS),
    '{{PENALTY_AMOUNT}}':      nda.PENALTY_AMOUNT_EUR !== null ? str(nda.PENALTY_AMOUNT_EUR) : '',

    // --- CONSENT ---
    '{{WEBSITE_NAME}}':        con.WEBSITE_NAME || str(p.WEBSITE_URL),
    '{{ANALYTICS_TOOLS}}':     str(con.ANALYTICS_TOOLS),
    '{{MARKETING_PARTNERS}}':  str(con.MARKETING_PARTNERS),

    // --- ALIASES (canonical names from new templates) ---
    '{{COMPANY_LEGAL_NAME}}':  str(p.LEGAL_NAME),
    '{{COMPANY_LEGAL_FORM}}':  str(p.LEGAL_FORM),
    '{{COMPANY_ADDRESS_LINE}}': str(p.ADDRESS_LINE),
    '{{COMPANY_POSTAL_CODE}}': str(p.POSTAL_CODE),
    '{{COMPANY_CITY}}':        str(p.CITY),
    '{{COMPANY_COUNTRY}}':     str(p.COUNTRY),
    '{{COMPANY_ADDRESS_FULL}}': [p.ADDRESS_LINE, [p.POSTAL_CODE, p.CITY].filter(Boolean).join(' '), p.COUNTRY].filter(Boolean).join(', '),
    '{{WEBSITE_URL}}':         str(p.WEBSITE_URL),
    '{{CONTACT_PHONE}}':       str(p.PHONE),
    '{{REPRESENTED_BY_NAME}}': str(p.CEO_NAME),
    '{{REGISTER_COURT}}':      str(p.REGISTER_COURT),
    '{{REGISTER_NUMBER}}':     str(p.REGISTER_NUMBER),
    '{{VAT_ID}}':              str(p.VAT_ID),
    '{{SERVICE_DESCRIPTION_SHORT}}': str(s.DESCRIPTION),
    '{{NOTICE_PERIOD_DAYS}}':  str(s.TERMINATION_NOTICE_DAYS),
    '{{ANALYTICS_TOOLS_LIST}}': str(con.ANALYTICS_TOOLS),
    '{{MARKETING_PARTNERS_LIST}}': str(con.MARKETING_PARTNERS),
    '{{DATA_PROCESSING_LOCATIONS}}': str(s.DATA_LOCATION),
    '{{SUPERVISORY_AUTHORITY_NAME}}': str(prv.SUPERVISORY_AUTHORITY_NAME),
    '{{SUPERVISORY_AUTHORITY_ADDRESS}}': str(prv.SUPERVISORY_AUTHORITY_ADDRESS),

    // --- HOSTING ---
    '{{HOSTING_PROVIDER_NAME}}':    str(h.PROVIDER_NAME),
    '{{HOSTING_PROVIDER_COUNTRY}}': str(h.COUNTRY),
    '{{HOSTING_PROVIDER_CONTRACT_TYPE}}': str(h.CONTRACT_TYPE),

    // --- FEATURES (text fields) ---
    '{{CONSENT_WITHDRAWAL_PATH}}':       str(f.CONSENT_WITHDRAWAL_PATH),
    '{{SECURITY_MEASURES_SUMMARY}}':     str(f.SECURITY_MEASURES_SUMMARY),
    '{{DATA_SUBJECT_REQUEST_CHANNEL}}':  str(f.DATA_SUBJECT_REQUEST_CHANNEL),
    '{{TRANSFER_GUARDS}}':               str(f.TRANSFER_GUARDS),
    '{{REGULATED_PROFESSION_TEXT}}':     str(f.REGULATED_PROFESSION_TEXT),
    '{{EDITORIAL_RESPONSIBLE_NAME}}':    str(f.EDITORIAL_RESPONSIBLE_NAME),
    '{{EDITORIAL_RESPONSIBLE_ADDRESS}}': str(f.EDITORIAL_RESPONSIBLE_ADDRESS),
    '{{DISPUTE_RESOLUTION_TEXT}}':       str(f.DISPUTE_RESOLUTION_TEXT),
    '{{NEWSLETTER_PROVIDER_DETAIL}}':    str(f.NEWSLETTER_PROVIDER_DETAIL),
    '{{PAYMENT_PROVIDER_DETAIL}}':       str(f.PAYMENT_PROVIDER_DETAIL),
    '{{SOCIAL_MEDIA_DETAIL}}':           str(f.SOCIAL_MEDIA_DETAIL),
    '{{ANALYTICS_TOOLS_DETAIL}}':        str(f.ANALYTICS_TOOLS_DETAIL),
    '{{MARKETING_TOOLS_DETAIL}}':        str(f.MARKETING_TOOLS_DETAIL),
    '{{CMP_NAME}}':                      str(f.CMP_NAME),
    '{{PRICES_TEXT}}':                   str(f.PRICES_TEXT),
    '{{PAYMENT_TERMS_TEXT}}':            str(f.PAYMENT_TERMS_TEXT),
    '{{CONTRACT_TERM_TEXT}}':            str(f.CONTRACT_TERM_TEXT),
    '{{SLA_URL}}':                       str(f.SLA_URL),
    '{{EXPORT_POLICY_TEXT}}':            str(f.EXPORT_POLICY_TEXT),
    '{{LIMITATION_CAP_TEXT}}':           str(f.LIMITATION_CAP_TEXT),
    '{{CONSUMER_WITHDRAWAL_TEXT}}':      str(f.CONSUMER_WITHDRAWAL_TEXT),
    '{{SUPPORT_CHANNELS_TEXT}}':         str(f.SUPPORT_CHANNELS_TEXT),

    // --- TOM ---
    '{{ISB_NAME}}':              str(tom.ISB_NAME),
    '{{GF_NAME}}':               str(tom.GF_NAME),
    '{{DOCUMENT_VERSION}}':      str(tom.DOCUMENT_VERSION),
    '{{NEXT_REVIEW_DATE}}':      str(tom.NEXT_REVIEW_DATE),

    // --- DPA / AVV ---
    '{{AG_NAME}}':               str(dpa.AG_NAME) || str(c.LEGAL_NAME),
    '{{AG_STRASSE}}':            str(dpa.AG_STRASSE) || str(c.ADDRESS_LINE),
    '{{AG_PLZ_ORT}}':            str(dpa.AG_PLZ_ORT) || [c.POSTAL_CODE, c.CITY].filter(Boolean).join(' '),
    '{{AN_NAME}}':               str(dpa.AN_NAME) || str(p.LEGAL_NAME),
    '{{AN_STRASSE}}':            str(dpa.AN_STRASSE) || str(p.ADDRESS_LINE),
    '{{AN_PLZ_ORT}}':            str(dpa.AN_PLZ_ORT) || [p.POSTAL_CODE, p.CITY].filter(Boolean).join(' '),
    '{{VERARBEITUNGSGEGENSTAND}}': str(dpa.VERARBEITUNGSGEGENSTAND),
    '{{VERARBEITUNGSZWECK}}':    str(dpa.VERARBEITUNGSZWECK),
    '{{VERARBEITUNGSARTEN}}':    str(dpa.VERARBEITUNGSARTEN),
    '{{DATENKATEGORIEN}}':       str(dpa.DATENKATEGORIEN),
    '{{PERSONENKATEGORIEN}}':    str(dpa.PERSONENKATEGORIEN),
    '{{BREACH_NOTIFICATION_HOURS}}': str(dpa.BREACH_NOTIFICATION_HOURS) || str(sec.INCIDENT_NOTICE_HOURS),
    '{{INSTRUCTION_RETENTION_YEARS}}': str(dpa.INSTRUCTION_RETENTION_YEARS),
    '{{SUB_PROCESSOR_NOTICE_WEEKS}}': str(dpa.SUB_PROCESSOR_NOTICE_WEEKS),
    '{{SUB_PROCESSOR_OBJECTION_WEEKS}}': str(dpa.SUB_PROCESSOR_OBJECTION_WEEKS),
    '{{DATA_EXPORT_FORMAT}}':    str(dpa.DATA_EXPORT_FORMAT),
    '{{RETURN_CHOICE_WEEKS}}':   str(dpa.RETURN_CHOICE_WEEKS),
    '{{DELETION_DAYS}}':         str(dpa.DELETION_DAYS),
    '{{REACTIVATION_MONTHS}}':   str(dpa.REACTIVATION_MONTHS),
    '{{TERMINATION_WEEKS}}':     str(dpa.TERMINATION_WEEKS),
    '{{CHANGE_NOTICE_WEEKS}}':   str(dpa.CHANGE_NOTICE_WEEKS),
    '{{THIRD_COUNTRY_OBJECTION_WEEKS}}': str(dpa.THIRD_COUNTRY_OBJECTION_WEEKS),
    '{{AN_DSB_NAME}}':           str(dpa.AN_DSB_NAME) || str(prv.DPO_NAME),
    '{{AN_DSB_EMAIL}}':          str(dpa.AN_DSB_EMAIL) || str(prv.DPO_EMAIL),
    '{{AG_ORT}}':                str(dpa.AG_ORT),
    '{{AN_ORT}}':                str(dpa.AN_ORT),
    '{{VERTRAGSDATUM}}':         str(dpa.VERTRAGSDATUM) || str(l.VERSION_DATE),
    '{{AG_UNTERZEICHNER_NAME}}': str(dpa.AG_UNTERZEICHNER_NAME),
    '{{AG_UNTERZEICHNER_FUNKTION}}': str(dpa.AG_UNTERZEICHNER_FUNKTION),
    '{{AN_UNTERZEICHNER_NAME}}': str(dpa.AN_UNTERZEICHNER_NAME) || str(p.CEO_NAME),
    '{{AN_UNTERZEICHNER_FUNKTION}}': str(dpa.AN_UNTERZEICHNER_FUNKTION),
    '{{GERICHTSSTAND}}':         str(dpa.GERICHTSSTAND) || str(l.JURISDICTION_CITY),

    // --- FEATURES: Whistleblower ---
    '{{WHISTLEBLOWER_CONTACT_NAME}}': str(f.WHISTLEBLOWER_CONTACT_NAME),
    '{{WHISTLEBLOWER_CONTACT_ROLE}}': str(f.WHISTLEBLOWER_CONTACT_ROLE),
    '{{WHISTLEBLOWER_EMAIL}}':   str(f.WHISTLEBLOWER_EMAIL),
    '{{WHISTLEBLOWER_PHONE}}':   str(f.WHISTLEBLOWER_PHONE),
    '{{WHISTLEBLOWER_URL}}':     str(f.WHISTLEBLOWER_URL),
    // --- FEATURES: Video Conference ---
    '{{VIDEO_PROVIDER_NAME}}':   str(f.VIDEO_PROVIDER_NAME),
    '{{VIDEO_PROVIDER_COUNTRY}}': str(f.VIDEO_PROVIDER_COUNTRY),
    '{{VIDEO_PROVIDER_ROLE}}':   str(f.VIDEO_PROVIDER_ROLE),
    '{{VIDEO_PROVIDER_PRIVACY_URL}}': str(f.VIDEO_PROVIDER_PRIVACY_URL),
    '{{RECORDING_RETENTION_DAYS}}': str(f.RECORDING_RETENTION_DAYS),
    // --- FEATURES: KI/AI ---
    '{{APPROVED_AI_SYSTEMS}}':   str(f.APPROVED_AI_SYSTEMS),
    // --- FEATURES: BYOD ---
    '{{BYOD_COST_DETAILS}}':     str(f.BYOD_COST_DETAILS),
    // --- FEATURES: Consent ---
    '{{NEWSLETTER_SIGNUP_URL}}': str(f.NEWSLETTER_SIGNUP_URL),
    // --- FEATURES: Social Media ---
    '{{SOCIAL_MEDIA_PLATFORMS_LIST}}': str(f.SOCIAL_MEDIA_PLATFORMS_LIST),
    '{{EDITORIAL_EMAIL}}':       str(f.EDITORIAL_EMAIL),
    // --- FEATURES: Transfer/SCC ---
    '{{RECIPIENT_NAME}}':        str(f.RECIPIENT_NAME),
    '{{RECIPIENT_COUNTRY}}':     str(f.RECIPIENT_COUNTRY),
    '{{RECIPIENT_ADDRESS}}':     str(f.RECIPIENT_ADDRESS),
    '{{RECIPIENT_CONTACT}}':     str(f.RECIPIENT_CONTACT),
    '{{RECIPIENT_EMAIL}}':       str(f.RECIPIENT_EMAIL),
    '{{RECIPIENT_ROLE}}':        str(f.RECIPIENT_ROLE),
    '{{TRANSFER_PURPOSE}}':      str(f.TRANSFER_PURPOSE),
    '{{TRANSFER_MECHANISM}}':    str(f.TRANSFER_MECHANISM),
    '{{DATA_CATEGORIES_TRANSFERRED}}': str(f.DATA_CATEGORIES_TRANSFERRED),
    '{{DATA_SUBJECTS}}':         str(f.DATA_SUBJECTS),
    '{{TRANSFER_FREQUENCY}}':    str(f.TRANSFER_FREQUENCY),
    // --- FEATURES: DSI ---
    '{{DSI_TITLE}}':             str(f.DSI_TITLE) || 'Datenschutzerklaerung',
    '{{SERVICE_SCOPE_DESCRIPTION}}': str(f.SERVICE_SCOPE_DESCRIPTION),
    '{{FULFILLMENT_LOCATION}}':  str(f.FULFILLMENT_LOCATION),
    '{{GUIDELINES_URL}}':        str(f.GUIDELINES_URL),
    '{{PROCESSOR_LIST_URL}}':    str(f.PROCESSOR_LIST_URL),
  }
}

// =============================================================================
// Computed flags
// =============================================================================

export function computeFlags(ctx: TemplateContext): ComputedFlags {
  return {
    IS_B2C:           ctx.CUSTOMER.IS_CONSUMER,
    IS_B2B:           ctx.CUSTOMER.IS_BUSINESS,
    SERVICE_IS_SAAS:  ctx.SERVICE.MODEL === 'SaaS',
    SERVICE_IS_HYBRID: ctx.SERVICE.MODEL === 'Hybrid',
    HAS_PENALTY:      ctx.NDA.PENALTY_AMOUNT_EUR !== null && ctx.NDA.PENALTY_AMOUNT_EUR !== '',
    HAS_ANALYTICS:    !!ctx.CONSENT.ANALYTICS_TOOLS,
    HAS_MARKETING:    !!ctx.CONSENT.MARKETING_PARTNERS,
  }
}

// =============================================================================
// Section relevance — which sections are useful for a given template
// =============================================================================

/** All placeholder patterns covered by each context section */
const SECTION_COVERS: Record<keyof TemplateContext, string[]> = {
  PROVIDER:  ['{{COMPANY_NAME}}', '{{PROVIDER_NAME}}', '{{DISCLOSING_PARTY}}', '{{SERVICE_PROVIDER}}', '{{COMPANY_ADDRESS}}', '{{PROVIDER_ADDRESS}}', '{{CONTACT_EMAIL}}', '{{PROVIDER_EMAIL}}', '{{ABUSE_EMAIL}}', '{{REPORT_EMAIL}}', '{{COMPANY_LEGAL_NAME}}', '{{COMPANY_LEGAL_FORM}}', '{{COMPANY_ADDRESS_LINE}}', '{{COMPANY_POSTAL_CODE}}', '{{COMPANY_CITY}}', '{{COMPANY_COUNTRY}}', '{{COMPANY_ADDRESS_FULL}}', '{{WEBSITE_URL}}', '{{CONTACT_PHONE}}', '{{REPRESENTED_BY_NAME}}', '{{REGISTER_COURT}}', '{{REGISTER_NUMBER}}', '{{VAT_ID}}'],
  CUSTOMER:  ['{{CUSTOMER_NAME}}', '{{RECEIVING_PARTY}}', '{{CUSTOMER}}'],
  SERVICE:   ['{{SERVICE_NAME}}', '{{PLATFORM_NAME}}', '{{SERVICE_DESCRIPTION}}', '{{SERVICE_MODEL}}', '{{SERVICE_TIER}}', '{{DATA_LOCATION}}', '{{EXPORT_FORMATS}}', '{{EXPORT_WINDOW_DAYS}}', '{{MIN_TERM_MONTHS}}', '{{TERMINATION_NOTICE_DAYS}}', '{{SERVICE_DESCRIPTION_SHORT}}', '{{NOTICE_PERIOD_DAYS}}', '{{DATA_PROCESSING_LOCATIONS}}'],
  LEGAL:     ['{{GOVERNING_LAW}}', '{{JURISDICTION_CITY}}', '{{VERSION_DATE}}', '{{EFFECTIVE_DATE}}', '{{START_DATE}}'],
  PRIVACY:   ['{{PRIVACY_CONTACT_EMAIL}}', '{{DPO_NAME}}', '{{DPO_EMAIL}}', '{{COPYRIGHT_CONTACT_NAME}}', '{{COPYRIGHT_EMAIL}}', '{{PRIVACY_POLICY_URL}}', '{{COOKIE_POLICY_URL}}', '{{ANALYTICS_RETENTION_MONTHS}}', '{{DATA_TRANSFER_THIRD_COUNTRIES}}', '{{SUPERVISORY_AUTHORITY_NAME}}', '{{SUPERVISORY_AUTHORITY_ADDRESS}}'],
  SLA:       ['{{AVAILABILITY_PERCENT}}', '{{MAINTENANCE_NOTICE_HOURS}}', '{{SUPPORT_EMAIL}}', '{{SUPPORT_PHONE}}', '{{SUPPORT_HOURS}}', '{{RESPONSE_CRITICAL_H}}', '{{RESOLUTION_CRITICAL_H}}', '{{RESPONSE_HIGH_H}}', '{{RESOLUTION_HIGH_H}}', '{{RESPONSE_MEDIUM_H}}', '{{RESOLUTION_MEDIUM_H}}', '{{RESPONSE_LOW_H}}'],
  PAYMENTS:  ['{{MONTHLY_FEE}}', '{{PAYMENT_DUE_DAY}}', '{{PAYMENT_METHOD}}', '{{PAYMENT_DAYS}}'],
  SECURITY:  ['{{INCIDENT_NOTICE_HOURS}}', '{{LOG_RETENTION_DAYS}}', '{{SECURITY_LOG_RETENTION_DAYS}}'],
  NDA:       ['{{PURPOSE}}', '{{DURATION_YEARS}}', '{{PENALTY_AMOUNT}}'],
  CONSENT:   ['{{WEBSITE_NAME}}', '{{ANALYTICS_TOOLS}}', '{{MARKETING_PARTNERS}}', '{{ANALYTICS_TOOLS_LIST}}', '{{MARKETING_PARTNERS_LIST}}'],
  HOSTING:   ['{{HOSTING_PROVIDER_NAME}}', '{{HOSTING_PROVIDER_COUNTRY}}', '{{HOSTING_PROVIDER_CONTRACT_TYPE}}'],
  FEATURES:  ['{{CONSENT_WITHDRAWAL_PATH}}', '{{SECURITY_MEASURES_SUMMARY}}', '{{DATA_SUBJECT_REQUEST_CHANNEL}}', '{{TRANSFER_GUARDS}}', '{{REGULATED_PROFESSION_TEXT}}', '{{EDITORIAL_RESPONSIBLE_NAME}}', '{{EDITORIAL_RESPONSIBLE_ADDRESS}}', '{{DISPUTE_RESOLUTION_TEXT}}', '{{NEWSLETTER_PROVIDER_DETAIL}}', '{{PAYMENT_PROVIDER_DETAIL}}', '{{SOCIAL_MEDIA_DETAIL}}', '{{ANALYTICS_TOOLS_DETAIL}}', '{{MARKETING_TOOLS_DETAIL}}', '{{CMP_NAME}}', '{{PRICES_TEXT}}', '{{PAYMENT_TERMS_TEXT}}', '{{CONTRACT_TERM_TEXT}}', '{{SLA_URL}}', '{{EXPORT_POLICY_TEXT}}', '{{LIMITATION_CAP_TEXT}}', '{{CONSUMER_WITHDRAWAL_TEXT}}', '{{SUPPORT_CHANNELS_TEXT}}', '{{WHISTLEBLOWER_CONTACT_NAME}}', '{{WHISTLEBLOWER_EMAIL}}', '{{WHISTLEBLOWER_URL}}', '{{VIDEO_PROVIDER_NAME}}', '{{APPROVED_AI_SYSTEMS}}', '{{SOCIAL_MEDIA_PLATFORMS_LIST}}', '{{DSI_TITLE}}', '{{SERVICE_SCOPE_DESCRIPTION}}', '{{GUIDELINES_URL}}', '{{PROCESSOR_LIST_URL}}', '{{RECIPIENT_NAME}}', '{{RECIPIENT_COUNTRY}}', '{{TRANSFER_PURPOSE}}', '{{TRANSFER_MECHANISM}}'],
  TOM:       ['{{ISB_NAME}}', '{{GF_NAME}}', '{{DOCUMENT_VERSION}}', '{{NEXT_REVIEW_DATE}}'],
  DPA:       ['{{AG_NAME}}', '{{AG_STRASSE}}', '{{AG_PLZ_ORT}}', '{{AN_NAME}}', '{{AN_STRASSE}}', '{{AN_PLZ_ORT}}', '{{VERARBEITUNGSGEGENSTAND}}', '{{VERARBEITUNGSZWECK}}', '{{VERARBEITUNGSARTEN}}', '{{DATENKATEGORIEN}}', '{{PERSONENKATEGORIEN}}', '{{BREACH_NOTIFICATION_HOURS}}', '{{INSTRUCTION_RETENTION_YEARS}}', '{{SUB_PROCESSOR_NOTICE_WEEKS}}', '{{SUB_PROCESSOR_OBJECTION_WEEKS}}', '{{DATA_EXPORT_FORMAT}}', '{{RETURN_CHOICE_WEEKS}}', '{{DELETION_DAYS}}', '{{REACTIVATION_MONTHS}}', '{{TERMINATION_WEEKS}}', '{{AN_DSB_NAME}}', '{{AN_DSB_EMAIL}}', '{{AG_ORT}}', '{{AN_ORT}}', '{{VERTRAGSDATUM}}', '{{AG_UNTERZEICHNER_NAME}}', '{{AG_UNTERZEICHNER_FUNKTION}}', '{{AN_UNTERZEICHNER_NAME}}', '{{AN_UNTERZEICHNER_FUNKTION}}', '{{GERICHTSSTAND}}'],
}

/**
 * Returns which context sections are relevant for a given list of template placeholders.
 */
export function getRelevantSections(placeholders: string[]): (keyof TemplateContext)[] {
  const pSet = new Set(placeholders)
  return (Object.keys(SECTION_COVERS) as (keyof TemplateContext)[]).filter(
    (section) => SECTION_COVERS[section].some((ph) => pSet.has(ph))
  )
}

/**
 * Returns a list of placeholder keys that are NOT covered by the context bridge.
 * These need to be filled in manually.
 */
export function getUncoveredPlaceholders(placeholders: string[], ctx: TemplateContext): string[] {
  const bridged = contextToPlaceholders(ctx)
  return placeholders.filter((ph) => !(ph in bridged))
}

/**
 * Strict validation: returns placeholder keys that are required but empty.
 * "Required" means: placeholder appears in template AND bridge covers it AND bridge produces empty string.
 */
export function getMissingRequired(placeholders: string[], ctx: TemplateContext): string[] {
  const bridged = contextToPlaceholders(ctx)
  return placeholders.filter((ph) => ph in bridged && !bridged[ph])
}

// =============================================================================
// Helpers to set nested context values by dot-path
// =============================================================================

/**
 * Returns a new TemplateContext with the value at dotPath set.
 * e.g. setContextPath(ctx, 'PROVIDER.LEGAL_NAME', 'ACME GmbH')
 */
export function setContextPath(ctx: TemplateContext, dotPath: string, value: unknown): TemplateContext {
  const [section, ...rest] = dotPath.split('.') as [keyof TemplateContext, ...string[]]
  const key = rest.join('.')
  return {
    ...ctx,
    [section]: {
      ...(ctx[section] as unknown as Record<string, unknown>),
      [key]: value,
    },
  }
}

/**
 * Get a nested context value by dot-path.
 */
export function getContextPath(ctx: TemplateContext, dotPath: string): unknown {
  const [section, ...rest] = dotPath.split('.') as [keyof TemplateContext, ...string[]]
  const sectionObj = ctx[section] as unknown as Record<string, unknown>
  return sectionObj?.[rest.join('.')]
}
