import { useEffect, useMemo, useState } from 'react'
import { AlertTriangle, CheckCircle2, HelpCircle, PenSquare } from 'lucide-react'
import { Button, Card, Loader } from '../../components/common'
import { endpoints, getErrorMessage } from '../../api/client'
import { t, tf } from '../../lib/i18n'
import type { MetaField, PostStructure, Reporter, SavedTechnicalRules } from '../../types'
import type { GenerationConfig } from '../../components/generator'
import { ConversationPhaseStep } from './ConversationPhaseStep'
import {
  createEmptyTechnicalState,
  extractTechnicalStateFromSavedRules,
  getTechnicalClarificationCount,
  getTechnicalFieldMappingByCategory,
  mergeTechnicalFieldMapping,
  normalizeTechnicalFieldForEditing,
  normalizeTechnicalFieldMapping,
  normalizeOpenQuestions,
  type TechnicalContentStructureSection,
  type TechnicalFieldDiagnosis,
  type TechnicalFieldFillBehavior,
  type TechnicalFieldMappingEntry,
} from './conversation-utils'

interface TechnicalStepProps {
  config: GenerationConfig
  reporter: Reporter | null
  savedRules: SavedTechnicalRules | null
  forceEdit: boolean
  sessionId: string | null
  initialState: Record<string, unknown>
  useSprintMode?: boolean
  onSessionChange: (sessionId: string) => void
  onStateChange: (state: Record<string, unknown>) => void
  onBack: () => void
  onUseSavedRules: () => void
  onEditSavedRules: () => void
  onContinue: (state: Record<string, unknown>) => void
  onSkip: () => void
}

interface TechnicalSampleSeo {
  plugin?: string
  meta_title?: string
  meta_description?: string
  focus_keyword?: string
}

interface TechnicalSampleFeaturedImage {
  id?: number | null
  url?: string
}

interface TechnicalSample {
  id?: number
  title?: string
  content?: string
  excerpt?: string
  meta?: Record<string, unknown>
  seo?: TechnicalSampleSeo
  featured_image?: TechnicalSampleFeaturedImage | null
}

const CAPTURED_KEY_TRANSLATIONS: Record<string, string> = {
  post_content_structure: 'Post content structure',
  seo_fields_generation: 'SEO fields generation',
  featured_image_generation: 'Featured image generation',
  excerpt_generation: 'Excerpt generation',
  content_structure: 'Content structure',
  content_structure_flexibility: 'Content structure flexibility',
  content_length: 'Content length',
  body_structure: 'Body structure',
  gallery_images: 'Gallery images',
  taxonomy_assignment: 'Taxonomy assignment',
  category_assignment: 'Category assignment',
  meta_fields_handling: 'Meta fields handling',
  field_fill_strategy: 'Field fill strategy',
  excerpt_handling: 'Excerpt handling',
  image_generation: 'Image generation',
  seo_handling: 'SEO handling',
  seo_and_image_generation: 'SEO and image generation',
  seo_fields: 'SEO fields',
  seo_generation: 'SEO generation',
  generate_seo_fields: 'Generate SEO fields',
  content_flexibility: 'Content flexibility',
  structure_flexibility: 'Structure flexibility',
  fill_behavior: 'Fill behavior',
  footnotes_usage: 'Footnotes usage',
  footnotes_handling: 'Footnotes handling',
  footnotes: 'Footnotes',
  generate_footnotes: 'Generate footnotes',
  internal_links: 'Internal links',
  external_links: 'External links',
  linking_strategy: 'Linking strategy',
  featured_image: 'Featured image',
  generate_featured_image: 'Generate featured image',
  excerpt: 'Excerpt',
  generate_excerpt: 'Generate excerpt',
  post_author: 'Post author',
  author: 'Author',
  question_id: 'Question',
  answer: 'Answer',
  field: 'Field',
  scope: 'Scope',
  rule: 'Rule',
  value: 'Value',
}

const CAPTURED_VALUE_TRANSLATIONS: Record<string, string> = {
  completely_flexible: 'Completely flexible',
  always_generate: 'Always generate',
  never_generate: 'Never generate',
  generate_when_missing: 'Generate when missing',
  follow_pattern: 'Follow pattern',
  follow_existing_pattern: 'Follow existing pattern',
  always_fill: 'Always fill',
  fill_when_relevant: 'Fill when relevant',
  do_not_fill: 'Do not fill',
  skip: 'Skip',
  skipped: 'Skipped',
  always: 'Always',
  never: 'Never',
  when_relevant: 'When relevant',
  strict: 'Strict',
  varied: 'Varied',
  free: 'Free',
  flexible: 'Flexible',
  strict_structure: 'Strict structure',
  flexible_structure: 'Flexible structure',
  yes: 'Yes',
  no: 'No',
  enabled: 'Enabled',
  disabled: 'Disabled',
  relevant: 'When relevant',
  choose_from_existing: 'Choose from existing',
  never_generate_footnotes: 'Never generate footnotes',
  always_generate_footnotes: 'Always generate footnotes',
  generate_when_relevant: 'Generate when relevant',
  auto: 'Auto',
}

function translateCapturedKey(raw: string): string {
  const exactKey = raw.trim().toLowerCase().replace(/\s+/g, '_')
  if (CAPTURED_KEY_TRANSLATIONS[exactKey]) {
    return t(CAPTURED_KEY_TRANSLATIONS[exactKey])
  }

  for (const [dictKey, translation] of Object.entries(CAPTURED_KEY_TRANSLATIONS)) {
    if (exactKey.includes(dictKey) || dictKey.includes(exactKey)) {
      return t(translation)
    }
  }

  const cleaned = raw.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())
  return t(cleaned)
}

function translateCapturedValue(raw: string): string {
  const normalized = raw.trim().toLowerCase().replace(/\s+/g, '_')
  const englishKey = CAPTURED_VALUE_TRANSLATIONS[normalized]
  return englishKey ? t(englishKey) : raw.replace(/_/g, ' ')
}

function createBaseDiagnosis(partial?: Partial<TechnicalFieldDiagnosis>): TechnicalFieldDiagnosis {
  return {
    description: '',
    sample_values: [],
    fill_rate: '',
    pattern: '',
    gemini_plan: '',
    confidence: 'medium',
    needs_clarification: false,
    fill_behavior: 'relevant',
    ...partial,
  }
}

function formatSectionSource(source: TechnicalContentStructureSection['source']): string {
  return source === 'new' ? t('New section') : t('Found in samples')
}

function formatFillRate(filled: number, total: number): string {
  if (total <= 0) {
    return '0/0 (0%)'
  }

  return `${filled}/${total} (${Math.round((filled / total) * 100)}%)`
}

function stringifySampleValue(value: unknown): string {
  if (value === null || value === undefined) {
    return ''
  }

  if (Array.isArray(value)) {
    if (value.length === 0) {
      return ''
    }

    const preview = value
      .map((item) => stringifySampleValue(item))
      .filter(Boolean)
      .slice(0, 3)
      .join(', ')

    return preview || String(value.length)
  }

  if (typeof value === 'object') {
    const raw = value as Record<string, unknown>
    if (typeof raw.slug === 'string') {
      return raw.slug
    }
    if (typeof raw.name === 'string') {
      return raw.name
    }

    try {
      return JSON.stringify(value)
    } catch {
      return ''
    }
  }

  return String(value).trim()
}

function collectSampleValues(values: unknown[]): string[] {
  return values
    .map((value) => stringifySampleValue(value))
    .filter(Boolean)
    .slice(0, 5)
}

function countFilledValues(values: unknown[]): number {
  return values.filter((value) => stringifySampleValue(value) !== '').length
}

function buildCoreFieldMapping(samples: TechnicalSample[]): TechnicalFieldMappingEntry[] {
  const totalSamples = samples.length
  const titles = collectSampleValues(samples.map((sample) => sample.title))
  const excerpts = collectSampleValues(samples.map((sample) => sample.excerpt))
  const featuredIds = collectSampleValues(samples.map((sample) => sample.featured_image?.id))

  return [
    {
      field_key: 'post_title',
      field_label: t('Title'),
      field_type: 'text',
      field_source: 'core',
      diagnosis: createBaseDiagnosis({
        sample_values: titles,
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.title)), totalSamples),
      }),
    },
    {
      field_key: 'post_content',
      field_label: t('Main Content'),
      field_type: 'wysiwyg',
      field_source: 'core',
      diagnosis: createBaseDiagnosis({
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.content)), totalSamples),
        content_structure: {
          common_sections: [],
          structure_flexibility: 'varied',
          note: '',
        },
      }),
    },
    {
      field_key: 'post_excerpt',
      field_label: t('Excerpt'),
      field_type: 'textarea',
      field_source: 'core',
      diagnosis: createBaseDiagnosis({
        sample_values: excerpts,
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.excerpt)), totalSamples),
      }),
    },
    {
      field_key: '_thumbnail_id',
      field_label: t('Featured Image'),
      field_type: 'media',
      field_source: 'core',
      diagnosis: createBaseDiagnosis({
        sample_values: featuredIds,
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.featured_image?.id)), totalSamples),
      }),
    },
  ]
}

function buildSeoFieldMapping(samples: TechnicalSample[]): TechnicalFieldMappingEntry[] {
  const totalSamples = samples.length

  return [
    {
      field_key: '_yoast_wpseo_title',
      field_label: t('SEO Title'),
      field_type: 'text',
      field_source: 'seo',
      diagnosis: createBaseDiagnosis({
        sample_values: collectSampleValues(samples.map((sample) => sample.seo?.meta_title)),
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.seo?.meta_title)), totalSamples),
      }),
    },
    {
      field_key: '_yoast_wpseo_metadesc',
      field_label: t('Meta Description'),
      field_type: 'textarea',
      field_source: 'seo',
      diagnosis: createBaseDiagnosis({
        sample_values: collectSampleValues(samples.map((sample) => sample.seo?.meta_description)),
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.seo?.meta_description)), totalSamples),
      }),
    },
    {
      field_key: '_yoast_wpseo_focuskw',
      field_label: t('Focus Keyword'),
      field_type: 'text',
      field_source: 'seo',
      diagnosis: createBaseDiagnosis({
        sample_values: collectSampleValues(samples.map((sample) => sample.seo?.focus_keyword)),
        fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.seo?.focus_keyword)), totalSamples),
      }),
    },
  ]
}

function buildCustomFieldMapping(metaFields: MetaField[], samples: TechnicalSample[]): TechnicalFieldMappingEntry[] {
  const totalSamples = samples.length

  return metaFields.map((field) => ({
    field_key: field.name,
    field_label: field.title || field.name,
    field_type: field.type || 'text',
    field_source: field.source || 'custom',
    diagnosis: createBaseDiagnosis({
      sample_values: collectSampleValues(samples.map((sample) => sample.meta?.[field.name])),
      fill_rate: formatFillRate(countFilledValues(samples.map((sample) => sample.meta?.[field.name])), totalSamples),
      fill_behavior: field.required ? 'always' : 'relevant',
    }),
  }))
}

function buildFieldInventory(structure: PostStructure | null, samples: TechnicalSample[]): TechnicalFieldMappingEntry[] {
  if (!structure) {
    return []
  }

  return [
    ...buildCoreFieldMapping(samples),
    ...buildSeoFieldMapping(samples),
    ...buildCustomFieldMapping(structure.meta_fields || [], samples),
  ]
}

function getConfidenceBadge(confidence: string) {
  if (confidence === 'high') {
    return {
      label: t('Confidence: High'),
      icon: <CheckCircle2 className="h-4 w-4" />,
      className: 'bg-emerald-50 text-emerald-700 border border-emerald-200',
    }
  }

  if (confidence === 'low') {
    return {
      label: t('Confidence: Low'),
      icon: <HelpCircle className="h-4 w-4" />,
      className: 'bg-amber-50 text-amber-700 border border-amber-200',
    }
  }

  return {
    label: t('Confidence: Medium'),
    icon: <AlertTriangle className="h-4 w-4" />,
    className: 'bg-yellow-50 text-yellow-700 border border-yellow-200',
  }
}

function getFillBehaviorLabel(value: TechnicalFieldFillBehavior): string {
  if (value === 'always') {
    return t('Always fill')
  }

  if (value === 'never') {
    return t('Do not fill this field')
  }

  return t('Fill when relevant')
}

function getFieldKeyPreview(entries: TechnicalFieldMappingEntry[]): { visibleKeys: string[]; hiddenCount: number } {
  const keys = entries
    .map((entry) => entry.field_key.trim())
    .filter(Boolean)

  return {
    visibleKeys: keys.slice(0, 6),
    hiddenCount: Math.max(0, keys.length - 6),
  }
}

function FieldMappingRow({
  entry,
  isEditing,
  canEdit,
  onEdit,
  onCancel,
  onChange,
}: {
  entry: TechnicalFieldMappingEntry
  isEditing: boolean
  canEdit: boolean
  onEdit: () => void
  onCancel: () => void
  onChange: (nextEntry: TechnicalFieldMappingEntry) => void
}) {
  const normalized = normalizeTechnicalFieldForEditing(entry)
  const badge = getConfidenceBadge(normalized.diagnosis.confidence)
  const contentStructure = normalized.diagnosis.content_structure
  const seoNote = contentStructure?.note || t('SEO note: Google prefers structural variety between posts')

  return (
    <div className={`rounded-bc border bg-white p-4 ${normalized.diagnosis.needs_clarification ? 'border-amber-300 shadow-[0_0_0_1px_rgba(245,158,11,0.15)]' : 'border-bc-gray-200'}`}>
      <div className="flex flex-wrap items-start gap-3">
        <div className="min-w-0 flex-1">
          <div className="flex flex-wrap items-center gap-2">
            <code className="rounded bg-bc-gray-100 px-2 py-0.5 text-xs text-bc-gray-700">{normalized.field_key}</code>
            <span className="font-semibold text-bc-gray-800">{normalized.field_label}</span>
          </div>
          <div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-bc-gray-500">
            <span>{normalized.field_type}</span>
            <span>•</span>
            <span>{t('Field source')}: {t(normalized.field_source)}</span>
            <span>•</span>
            <span>{getFillBehaviorLabel(normalized.diagnosis.fill_behavior)}</span>
          </div>
        </div>

        <div className="ms-auto flex items-center gap-2">
          <span className={`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium ${badge.className}`}>
            {badge.icon}
            {badge.label}
          </span>
          {canEdit && !isEditing ? (
            <Button size="sm" variant="ghost" onClick={onEdit}>
              {t('Edit field rules')}
            </Button>
          ) : null}
        </div>
      </div>

      <div className="mt-3 space-y-2 text-sm text-bc-gray-700">
        <div>
          <span className="font-medium text-bc-gray-800">{t('Description')}:</span>{' '}
          <span>{normalized.diagnosis.description || '—'}</span>
        </div>
        <div>
          <span className="font-medium text-bc-gray-800">{t('Structural rule')}:</span>{' '}
          <span>{normalized.diagnosis.gemini_plan || '—'}</span>
        </div>
        <div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-bc-gray-600">
          <span>{t('Fill rate')}: {normalized.diagnosis.fill_rate || '—'}</span>
          <span>{t('Pattern detected')}: {normalized.diagnosis.pattern || '—'}</span>
        </div>

        {normalized.diagnosis.sample_values.length > 0 ? (
          <div>
            <div className="font-medium text-bc-gray-800">{t('Sample values')}</div>
            <div className="mt-1 flex flex-wrap gap-1">
              {normalized.diagnosis.sample_values.map((value, index) => (
                <span key={`${normalized.field_key}-${index}`} className="rounded-full bg-bc-gray-100 px-2 py-0.5 text-xs text-bc-gray-600">
                  {value}
                </span>
              ))}
            </div>
          </div>
        ) : null}

        {normalized.diagnosis.needs_clarification ? (
          <div className="rounded-bc border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800">
            <div className="font-medium">{t('Needs clarification')}</div>
            <div className="mt-1">{normalized.diagnosis.question || '—'}</div>
          </div>
        ) : null}

        {normalized.field_key === 'post_content' ? (
          <div className="rounded-bc border border-bc-gray-200 bg-bc-gray-50 p-3">
            <div className="font-medium text-bc-gray-800">{t('Content Structure')}</div>
            {contentStructure?.common_sections?.length ? (
              <div className="mt-2">
                <div className="text-xs font-medium text-bc-gray-600">{t('Common sections')}</div>
                <div className="mt-1 space-y-2">
                  {contentStructure.common_sections.map((section: TechnicalContentStructureSection, index: number) => (
                    <div key={`${normalized.field_key}-section-${index}`} className="rounded-bc bg-white px-2 py-2 text-xs text-bc-gray-600">
                      <div className="font-medium text-bc-gray-800">{section.heading || t('Unnamed section')}</div>
                      <div className="mt-1 flex flex-wrap gap-x-3 gap-y-1">
                        {section.type ? <span>{t('Section type')}: {section.type}</span> : null}
                        {section.frequency ? <span>{t('Frequency')}: {section.frequency}</span> : null}
                        {section.approx_length ? <span>{t('Approx. length')}: {section.approx_length}</span> : null}
                        <span>{t('Source')}: {formatSectionSource(section.source)}</span>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            ) : null}
            <div className="mt-2 text-xs text-bc-gray-600">
              {t('Structure Flexibility')}: {t(
                contentStructure?.structure_flexibility === 'strict'
                  ? 'Strict — follow detected pattern closely'
                  : contentStructure?.structure_flexibility === 'free'
                    ? 'Free — minimal structure guidance'
                    : 'Varied — use patterns as inspiration (recommended)',
              )}
            </div>
            <div className="mt-2 text-xs text-bc-gray-600">{seoNote}</div>
          </div>
        ) : null}
      </div>

      {isEditing ? (
        <div className="mt-4 rounded-bc border border-bc-gray-200 bg-bc-gray-50 p-3">
          <div className="grid gap-3">
            <div>
              <label className="mb-1 block text-xs font-medium text-bc-gray-700">{t('Description')}</label>
              <textarea
                rows={3}
                value={normalized.diagnosis.description}
                onChange={(event) => onChange({
                  ...normalized,
                  diagnosis: {
                    ...normalized.diagnosis,
                    description: event.target.value,
                  },
                })}
                className="w-full rounded-bc border border-bc-gray-300 px-3 py-2 text-sm"
              />
            </div>

            <div>
              <label className="mb-1 block text-xs font-medium text-bc-gray-700">{t('Structural rule')}</label>
              <textarea
                rows={3}
                value={normalized.diagnosis.gemini_plan}
                onChange={(event) => onChange({
                  ...normalized,
                  diagnosis: {
                    ...normalized.diagnosis,
                    gemini_plan: event.target.value,
                  },
                })}
                className="w-full rounded-bc border border-bc-gray-300 px-3 py-2 text-sm"
              />
            </div>

            <div>
              <label className="mb-1 block text-xs font-medium text-bc-gray-700">{t('Fill behavior')}</label>
              <select
                value={normalized.diagnosis.fill_behavior}
                onChange={(event) => onChange({
                  ...normalized,
                  diagnosis: {
                    ...normalized.diagnosis,
                    fill_behavior: event.target.value as TechnicalFieldFillBehavior,
                  },
                })}
                className="w-full rounded-bc border border-bc-gray-300 px-3 py-2 text-sm"
              >
                <option value="always">{t('Always fill')}</option>
                <option value="relevant">{t('Fill when relevant')}</option>
                <option value="never">{t('Do not fill this field')}</option>
              </select>
            </div>

            {normalized.field_key === 'post_content' ? (
              <div>
                <label className="mb-1 block text-xs font-medium text-bc-gray-700">{t('Structure Flexibility')}</label>
                <select
                  value={contentStructure?.structure_flexibility || 'varied'}
                  onChange={(event) => onChange({
                    ...normalized,
                    diagnosis: {
                      ...normalized.diagnosis,
                      content_structure: {
                        common_sections: contentStructure?.common_sections || [],
                        note: contentStructure?.note || '',
                        structure_flexibility: event.target.value as 'strict' | 'varied' | 'free',
                      },
                    },
                  })}
                  className="w-full rounded-bc border border-bc-gray-300 px-3 py-2 text-sm"
                >
                  <option value="strict">{t('Strict — follow detected pattern closely')}</option>
                  <option value="varied">{t('Varied — use patterns as inspiration (recommended)')}</option>
                  <option value="free">{t('Free — minimal structure guidance')}</option>
                </select>
              </div>
            ) : null}

            <div className="flex flex-wrap justify-end gap-2">
              <Button size="sm" variant="ghost" onClick={onCancel}>
                {t('Cancel editing')}
              </Button>
              <Button size="sm" onClick={onCancel}>
                {t('Save field changes')}
              </Button>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  )
}

function FieldMappingSection({
  title,
  entries,
  canEdit,
  editingFieldKey,
  onStartEdit,
  onCancelEdit,
  onEntryChange,
}: {
  title: string
  entries: TechnicalFieldMappingEntry[]
  canEdit: boolean
  editingFieldKey: string | null
  onStartEdit: (fieldKey: string) => void
  onCancelEdit: () => void
  onEntryChange: (entry: TechnicalFieldMappingEntry) => void
}) {
  if (entries.length === 0) {
    return null
  }

  const keyPreview = getFieldKeyPreview(entries)

  return (
    <details className="rounded-bc border border-bc-gray-200 bg-white">
      <summary className="cursor-pointer list-none px-4 py-3">
        <div className="flex flex-wrap items-center gap-2 text-bc-gray-800">
          <span className="text-sm font-semibold">
            {`${title} (${entries.length})`}
          </span>
          {keyPreview.visibleKeys.length > 0 ? <span className="text-sm font-semibold">:</span> : null}
          {keyPreview.visibleKeys.map((fieldKey) => (
            <span
              key={fieldKey}
              className="rounded-full bg-bc-gray-100 px-2 py-0.5 text-xs font-medium text-bc-gray-600"
            >
              {fieldKey}
            </span>
          ))}
          {keyPreview.hiddenCount > 0 ? (
            <span className="rounded-full bg-bc-gray-100 px-2 py-0.5 text-xs font-medium text-bc-gray-500">
              {tf('+%d more', keyPreview.hiddenCount)}
            </span>
          ) : null}
        </div>
      </summary>
      <div className="space-y-3 border-t border-bc-gray-200 px-4 py-4">
        {entries.map((entry) => (
          <FieldMappingRow
            key={entry.field_key}
            entry={entry}
            isEditing={editingFieldKey === entry.field_key}
            canEdit={canEdit}
            onEdit={() => onStartEdit(entry.field_key)}
            onCancel={onCancelEdit}
            onChange={onEntryChange}
          />
        ))}
      </div>
    </details>
  )
}

function FieldMappingPanel({
  samplesCount,
  fieldMapping,
  clarificationCount,
  canEdit,
  editingFieldKey,
  onStartEdit,
  onCancelEdit,
  onEntryChange,
}: {
  samplesCount: number
  fieldMapping: TechnicalFieldMappingEntry[]
  clarificationCount: number
  canEdit: boolean
  editingFieldKey: string | null
  onStartEdit: (fieldKey: string) => void
  onCancelEdit: () => void
  onEntryChange: (entry: TechnicalFieldMappingEntry) => void
}) {
  const groupedFields = getTechnicalFieldMappingByCategory(fieldMapping)

  return (
    <Card>
      <div className="rounded-bc border border-bc-gray-200 bg-white px-4 py-4">
        <div className="font-medium text-bc-gray-800">{t('Field Mapping')}</div>
        <div className="mt-1 text-xs text-bc-gray-500">
          {tf('Gemini analyzed %d sample posts and mapped %d fields', samplesCount, fieldMapping.length)}
        </div>
        <div className="mt-2 text-xs text-bc-gray-600">
          {clarificationCount > 0
            ? tf('%d fields need clarification', clarificationCount)
            : t('All fields mapped with high confidence')}
        </div>
      </div>

      {fieldMapping.length > 0 ? (
        <div className="mt-4 space-y-3">
          <FieldMappingSection
            title={t('Core Fields')}
            entries={groupedFields.core}
            canEdit={canEdit}
            editingFieldKey={editingFieldKey}
            onStartEdit={onStartEdit}
            onCancelEdit={onCancelEdit}
            onEntryChange={onEntryChange}
          />
          <FieldMappingSection
            title={t('SEO Fields')}
            entries={groupedFields.seo}
            canEdit={canEdit}
            editingFieldKey={editingFieldKey}
            onStartEdit={onStartEdit}
            onCancelEdit={onCancelEdit}
            onEntryChange={onEntryChange}
          />
          <FieldMappingSection
            title={t('Custom Fields')}
            entries={groupedFields.custom}
            canEdit={canEdit}
            editingFieldKey={editingFieldKey}
            onStartEdit={onStartEdit}
            onCancelEdit={onCancelEdit}
            onEntryChange={onEntryChange}
          />
        </div>
      ) : (
        <div className="mt-4 text-sm text-bc-gray-500">
          {t('No field mapping yet. Gemini will fill this after the technical analysis starts.')}
        </div>
      )}
    </Card>
  )
}

export function TechnicalStep({
  config,
  reporter,
  savedRules,
  forceEdit,
  sessionId,
  initialState,
  useSprintMode = false,
  onSessionChange,
  onStateChange,
  onBack,
  onUseSavedRules,
  onEditSavedRules,
  onContinue,
  onSkip,
}: TechnicalStepProps) {
  const technicalContinueLabel = useSprintMode
    ? t('Continue to intent collection')
    : t('Continue to content planning')
  const [structure, setStructure] = useState<PostStructure | null>(null)
  const [samples, setSamples] = useState<TechnicalSample[]>([])
  const [selectedTerms, setSelectedTerms] = useState<string[]>([])
  const [editingFieldKey, setEditingFieldKey] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [loadError, setLoadError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false

    void (async () => {
      setLoading(true)
      setLoadError(null)

      try {
        const [structureRes, samplesRes] = await Promise.all([
          endpoints.getStructure(config.postType),
          endpoints.getStructureSamples(config.postType),
        ])

        if (cancelled) {
          return
        }

        const nextStructure = structureRes.data as PostStructure
        setStructure(nextStructure)
        setSamples(((samplesRes.data as any)?.samples || []).slice(0, 5))

        if (config.taxonomy && config.term) {
          const termsRes = await endpoints.getTaxonomyTerms(config.postType, config.taxonomy)
          if (cancelled) {
            return
          }

          const selectedSlugs = config.term.split(',').filter(Boolean)
          const names = ((termsRes.data as any[]) || [])
            .filter((term) => selectedSlugs.includes(term.slug))
            .map((term) => term.name)
          setSelectedTerms(names)
        } else {
          setSelectedTerms([])
        }
      } catch (error) {
        if (!cancelled) {
          setLoadError(getErrorMessage(error, t('Error loading content types')))
        }
      } finally {
        if (!cancelled) {
          setLoading(false)
        }
      }
    })()

    return () => {
      cancelled = true
    }
  }, [config.postType, config.taxonomy, config.term])

  const fieldInventory = useMemo(
    () => buildFieldInventory(structure, samples),
    [samples, structure],
  )

  const seededInitialState = useMemo(() => ({
    ...createEmptyTechnicalState(),
    ...initialState,
    captured_answers: Array.isArray(initialState.captured_answers) ? initialState.captured_answers : [],
    open_questions: Array.isArray(initialState.open_questions) ? initialState.open_questions : [],
    field_mapping: mergeTechnicalFieldMapping(
      fieldInventory,
      normalizeTechnicalFieldMapping(initialState.field_mapping),
    ),
  }), [fieldInventory, initialState])

  const context = useMemo(() => {
    if (!structure) {
      return {}
    }

    return {
      post_type: {
        slug: structure.post_type,
        label: structure.post_type_label,
        core_fields: [
          { key: 'post_title', label: t('Title'), type: 'text', source: 'core' },
          { key: 'post_content', label: t('Main Content'), type: 'wysiwyg', source: 'core' },
          { key: 'post_excerpt', label: t('Excerpt'), type: 'textarea', source: 'core' },
          { key: '_thumbnail_id', label: t('Featured Image'), type: 'media', source: 'core' },
        ],
        seo_fields: buildSeoFieldMapping(samples).map((field) => ({
          key: field.field_key,
          label: field.field_label,
          type: field.field_type,
          source: field.field_source,
        })),
        meta_fields: structure.meta_fields || [],
      },
      field_inventory: fieldInventory,
      samples,
      taxonomy: config.taxonomy
        ? {
            name: config.taxonomy,
            selected_terms: selectedTerms,
          }
        : {},
      count_per_category: config.countPerCategory,
      reporter,
      saved_rules: savedRules
        ? {
            summary: savedRules.summary,
            rules: savedRules.rules,
            structure_hash: savedRules.structure_hash,
            still_valid: savedRules.still_valid,
          }
        : null,
    }
  }, [config.countPerCategory, config.taxonomy, fieldInventory, reporter, samples, savedRules, selectedTerms, structure])

  if (loading) {
    return (
      <div className="py-16 flex items-center justify-center">
        <Loader />
      </div>
    )
  }

  if (loadError || !structure) {
    return (
      <Card className="max-w-2xl mx-auto text-center py-12">
        <p className="text-bc-error mb-4">{t('Error loading content types')}</p>
        <p className="text-bc-gray-500 text-sm">{loadError || t('Unknown error')}</p>
      </Card>
    )
  }

  if (savedRules?.still_valid && !forceEdit && !sessionId) {
    const savedState = {
      ...extractTechnicalStateFromSavedRules(savedRules),
      field_mapping: mergeTechnicalFieldMapping(
        fieldInventory,
        extractTechnicalStateFromSavedRules(savedRules).field_mapping,
      ),
    }
    return (
      <div className="mx-auto max-w-6xl space-y-8">
        <Card className="mx-auto max-w-4xl">
          <h2 className="mb-2 text-2xl font-bold text-bc-gray-800">{t('Technical Questions')}</h2>
          <p className="mb-6 text-bc-gray-500">{t('Previously established rules')}</p>
          <div className="rounded-bc border border-bc-gray-200 bg-bc-gray-50 px-4 py-4 text-sm text-bc-gray-700 whitespace-pre-wrap">
            {savedRules.summary || '—'}
          </div>
          <div className="mt-6 flex flex-wrap justify-between gap-3">
            <div className="flex gap-2">
              <Button variant="ghost" onClick={onBack}>
                {t('Back')}
              </Button>
              <Button variant="ghost" onClick={onEditSavedRules} icon={<PenSquare className="w-4 h-4" />}>
                {t('Edit technical rules')}
              </Button>
            </div>
            <div className="flex gap-2">
              <Button variant="secondary" onClick={onSkip}>
                {t('Skip this phase')}
              </Button>
              <Button onClick={onUseSavedRules}>
                {technicalContinueLabel}
              </Button>
            </div>
          </div>
        </Card>

        <FieldMappingPanel
          samplesCount={samples.length}
          fieldMapping={savedState.field_mapping}
          clarificationCount={getTechnicalClarificationCount(savedState.field_mapping)}
          canEdit={false}
          editingFieldKey={null}
          onStartEdit={() => {}}
          onCancelEdit={() => {}}
          onEntryChange={() => {}}
        />
      </div>
    )
  }

  return (
    <ConversationPhaseStep
      mode="generation_technical"
      title={t('Technical Questions')}
      subtitle={t('Clarify field rules, empty values, and structure before writing')}
      assistantLabel={reporter?.name || undefined}
      sessionId={sessionId}
      initialStructuredState={seededInitialState}
      context={context}
      autoStartMessage="[SYSTEM] Begin technical analysis of the post type structure. Analyze the fields and samples in the provided context, identify the most important open structural questions, and ask your first questions using question_cards."
      onSessionChange={onSessionChange}
      onStateChange={onStateChange}
      onBack={onBack}
      onContinue={onContinue}
      onSkip={onSkip}
      continueLabel={technicalContinueLabel}
      skipLabel={t('Skip this phase')}
      renderSidebar={({ draftState }) => {
        const answers = Array.isArray(draftState.captured_answers) ? (draftState.captured_answers as Record<string, unknown>[]) : []
        const questions = normalizeOpenQuestions(draftState.open_questions)

        return (
          <div className="space-y-3 text-sm text-bc-gray-700">
            <div>
              <div className="font-medium text-bc-gray-800 mb-1">{t('Summary')}</div>
              <div className="text-bc-gray-600 whitespace-pre-wrap">{String(draftState.technical_summary || '—')}</div>
            </div>
            <div>
              <div className="font-medium text-bc-gray-800 mb-1">{t('Captured Answers')}</div>
              <div className="space-y-1">
                {answers.length > 0 ? answers.map((answer, index) => {
                  const rawQuestionId = String(answer.question_id || answer.field || answer.scope || '')
                  const rawAnswerValue = String(answer.answer || answer.rule || answer.value || '')
                  if (rawQuestionId && rawAnswerValue) {
                    const questionLabel = translateCapturedKey(rawQuestionId)
                    const answerLabel = translateCapturedValue(rawAnswerValue)
                    return (
                      <div key={index} className="rounded-bc bg-bc-gray-50 px-2 py-1 text-xs">
                        <span className="font-medium text-bc-gray-700">{questionLabel}:</span>{' '}
                        <span className="text-bc-gray-600">{answerLabel}</span>
                      </div>
                    )
                  }
                  const pairs = Object.entries(answer).filter(([, v]) => v !== undefined && v !== null)
                  return (
                    <div key={index} className="rounded-bc bg-bc-gray-50 px-2 py-1 text-xs">
                      {pairs.map(([k, v]) => (
                        <span key={k} className="me-2">
                          <span className="font-medium text-bc-gray-700">{translateCapturedKey(k)}:</span>{' '}
                          <span className="text-bc-gray-600">{translateCapturedValue(String(v))}</span>
                        </span>
                      ))}
                    </div>
                  )
                }) : <div className="text-bc-gray-500">—</div>}
              </div>
            </div>
            <div>
              <div className="font-medium text-bc-gray-800 mb-1">{t('Open Questions')}</div>
              <div className="space-y-1">
                {questions.length > 0 ? questions.map((question, index) => (
                  <div key={index} className="rounded-bc bg-bc-gray-50 px-2 py-1 text-xs">{question}</div>
                )) : <div className="text-bc-gray-500">—</div>}
              </div>
            </div>
          </div>
        )
      }}
      renderSecondaryPanel={({ draftState, updateDraftState }) => {
        const fieldMapping = mergeTechnicalFieldMapping(
          fieldInventory,
          normalizeTechnicalFieldMapping(draftState.field_mapping),
        )
        const clarificationCount = getTechnicalClarificationCount(fieldMapping)

        const handleFieldChange = (nextEntry: TechnicalFieldMappingEntry) => {
          updateDraftState((current) => {
            const currentState = {
              ...createEmptyTechnicalState(),
              ...current,
            }
            const currentFieldMapping = mergeTechnicalFieldMapping(
              fieldInventory,
              normalizeTechnicalFieldMapping(currentState.field_mapping),
            )

            return {
              ...currentState,
              field_mapping: currentFieldMapping.map((entry) => (
                entry.field_key === nextEntry.field_key
                  ? nextEntry
                  : entry
              )),
            }
          })
        }

        return (
          <FieldMappingPanel
            samplesCount={samples.length}
            fieldMapping={fieldMapping}
            clarificationCount={clarificationCount}
            canEdit
            editingFieldKey={editingFieldKey}
            onStartEdit={setEditingFieldKey}
            onCancelEdit={() => setEditingFieldKey(null)}
            onEntryChange={handleFieldChange}
          />
        )
      }}
    />
  )
}
