import React, { useCallback, useEffect, useMemo, useState } from 'react'
import type {
  CheckpointReplyMetadata,
  ChatMessageMeta,
  StaffingEmployeeOption,
  StaffingRoleEntry,
  StaffingSelectionValue,
  StaffingTemplateOption,
} from '../types/chat'
import type { TaskPreferredAgent } from '../types/kanban'

const TASK_AGENT_LABELS: Record<TaskPreferredAgent, string> = {
  native: 'OpenOPC Native',
  codex: 'Codex',
  claude_code: 'Claude Code',
  cursor: 'Cursor',
  opencode: 'OpenCode',
}

const DEFAULT_ROLE_AGENT: TaskPreferredAgent = 'codex'
const DEFAULT_RECRUITMENT_AGENT: TaskPreferredAgent = 'native'
const TASK_AGENT_OPTIONS: TaskPreferredAgent[] = ['codex', 'native', 'claude_code', 'cursor', 'opencode']
const RECRUITMENT_AGENT_OPTIONS: TaskPreferredAgent[] = ['native', 'codex', 'claude_code', 'cursor', 'opencode']

type StaffingOption =
  | { kind: 'employee'; id: string; name: string; subtitle: string; category: string; searchText: string }
  | { kind: 'template'; id: string; name: string; subtitle: string; category: string; searchText: string }
  | { kind: 'fallback'; id: ''; name: string; subtitle: string; category: string; searchText: string }

interface StaffingSelectionPanelProps {
  meta: ChatMessageMeta
  onReply: (text: string, metadata?: CheckpointReplyMetadata) => void
  responded: boolean
}

function normalizeSelection(value: StaffingSelectionValue | undefined): StaffingSelectionValue {
  if (!value) return { kind: 'fallback' }
  if (value.kind === 'employee') {
    const id = String(value.id ?? value.employee_id ?? '').trim()
    return id ? { kind: 'employee', id } : { kind: 'fallback' }
  }
  if (value.kind === 'template') {
    const id = String(value.id ?? value.template_id ?? '').trim()
    return id ? { kind: 'template', id } : { kind: 'fallback' }
  }
  return { kind: 'fallback' }
}

function selectionKey(value: StaffingSelectionValue | undefined): string {
  const normalized = normalizeSelection(value)
  return normalized.kind === 'fallback' ? 'fallback:' : `${normalized.kind}:${normalized.id ?? ''}`
}

function buildOptions(
  role: StaffingRoleEntry,
  employees: StaffingEmployeeOption[],
  templates: StaffingTemplateOption[],
): StaffingOption[] {
  const roleId = String(role.role_id ?? '').trim()
  const roleLabel = String(role.role_label ?? '').trim()
  const roleText = `${roleId} ${roleLabel} ${role.role_responsibility ?? ''}`.toLowerCase()
  const sameRoleIds = new Set((role.same_role_employee_ids ?? []).map(item => String(item ?? '').trim()).filter(Boolean))
  const templateScore = (template: StaffingTemplateOption): number => {
    const templateText = `${template.template_id ?? ''} ${template.template_name ?? ''} ${template.category ?? ''} ${(template.domains ?? []).join(' ')} ${(template.tags ?? []).join(' ')}`.toLowerCase()
    const categoryTerm = String(template.category ?? '').toLowerCase()
    let score = 0
    for (const token of roleText.split(/[^a-z0-9]+/).filter(token => token.length >= 3)) {
      if (templateText.includes(token) || (categoryTerm && token.includes(categoryTerm))) score += 1
    }
    if (templateText.includes(roleId.replace(/_/g, '-')) || templateText.includes(roleId.replace(/_/g, ' '))) score += 2
    return score
  }
  const employeeOptions = employees.map((employee): StaffingOption & { rank: number } => {
    const id = String(employee.employee_id ?? '').trim()
    const name = String(employee.employee_name ?? id).trim() || id
    const employeeRole = String(employee.role_id ?? '').trim()
    const category = String(employee.category ?? '').trim()
    const subtitle = [employeeRole, category].filter(Boolean).join(' · ') || id
    return {
      kind: 'employee',
      id,
      name,
      subtitle,
      category,
      searchText: `${id} ${name} ${employeeRole} ${category} ${(employee.domains ?? []).join(' ')} ${(employee.tags ?? []).join(' ')}`.toLowerCase(),
      rank: sameRoleIds.has(id) || employeeRole === roleId ? 0 : 2,
    }
  }).filter(option => option.id).sort((a, b) => a.rank - b.rank || a.name.localeCompare(b.name))
  const templateOptions = templates.map((template): StaffingOption & { rank: number } => {
    const id = String(template.template_id ?? '').trim()
    const name = String(template.template_name ?? id).trim() || id
    const category = String(template.category ?? '').trim()
    const subtitle = [category, id].filter(Boolean).join(' · ') || id
    return {
      kind: 'template',
      id,
      name,
      subtitle,
      category,
      searchText: `${id} ${name} ${category} ${(template.domains ?? []).join(' ')} ${(template.tags ?? []).join(' ')}`.toLowerCase(),
      rank: templateScore(template),
    }
  }).filter(option => option.id).sort((a, b) => b.rank - a.rank || a.name.localeCompare(b.name))
  return [
    ...employeeOptions,
    ...templateOptions,
    { kind: 'fallback', id: '', name: 'Fallback role-only', subtitle: 'No employee override', category: 'fallback', searchText: 'fallback role only no employee override' },
  ]
}

function optionForSelection(options: StaffingOption[], selection: StaffingSelectionValue | undefined): StaffingOption {
  const key = selectionKey(selection)
  return options.find(option => `${option.kind}:${option.id}` === key) ?? options[0]
}

function optionMatches(option: StaffingOption, query: string): boolean {
  const terms = query.toLowerCase().split(/\s+/).filter(Boolean)
  if (terms.length === 0) return true
  return terms.every(term => option.searchText.includes(term))
}

function buildSelectionsFromMeta(meta: ChatMessageMeta, roles: StaffingRoleEntry[]): Record<string, StaffingSelectionValue> {
  const initial: Record<string, StaffingSelectionValue> = {}
  const persisted = meta.staffing_selections ?? {}
  for (const role of roles) {
    const roleId = String(role.role_id ?? '').trim()
    if (!roleId) continue
    initial[roleId] = normalizeSelection(persisted[roleId] ?? role.default_selection)
  }
  return initial
}

function buildRoleAgentsFromMeta(meta: ChatMessageMeta, roles: StaffingRoleEntry[]): Record<string, TaskPreferredAgent> {
  const persisted = meta.recruitment_role_agents ?? {}
  const initial: Record<string, TaskPreferredAgent> = {}
  for (const role of roles) {
    const roleId = String(role.role_id ?? '').trim()
    if (!roleId) continue
    initial[roleId] = persisted[roleId] ?? role.selected_agent ?? role.default_agent ?? DEFAULT_ROLE_AGENT
  }
  return initial
}

function hasSubmittedCheckpointMetadata(meta: ChatMessageMeta): boolean {
  return Boolean(
    String(meta.checkpoint_response_message_id ?? '').trim()
    || String(meta.checkpoint_responded_at ?? '').trim()
    || String(meta.staffing_action ?? '').trim()
  )
}

export const StaffingSelectionPanel = React.memo(function StaffingSelectionPanel({
  meta, onReply, responded,
}: StaffingSelectionPanelProps) {
  const roles = useMemo(() => meta.staffing_roles ?? [], [meta.staffing_roles])
  const employees = meta.staffing_pool?.employees ?? []
  const templates = meta.staffing_pool?.templates ?? []
  const optionsByRole = useMemo(() => {
    const next: Record<string, StaffingOption[]> = {}
    for (const role of roles) {
      const roleId = String(role.role_id ?? '').trim()
      if (roleId) next[roleId] = buildOptions(role, employees, templates)
    }
    return next
  }, [employees, roles, templates])
  const [queries, setQueries] = useState<Record<string, string>>({})
  const [selections, setSelections] = useState<Record<string, StaffingSelectionValue>>(() => buildSelectionsFromMeta(meta, roles))
  const [roleAgents, setRoleAgents] = useState<Record<string, TaskPreferredAgent>>(() => buildRoleAgentsFromMeta(meta, roles))
  const [recruitmentAgent, setRecruitmentAgent] = useState<TaskPreferredAgent>(meta.recruitment_agent ?? DEFAULT_RECRUITMENT_AGENT)
  const isResponded = responded
  const recommendAutoRecruit = meta.recommended_action === 'auto_recruit' && templates.length > 0

  useEffect(() => {
    if (!isResponded || !hasSubmittedCheckpointMetadata(meta)) return
    setSelections(buildSelectionsFromMeta(meta, roles))
    setRoleAgents(buildRoleAgentsFromMeta(meta, roles))
    setRecruitmentAgent(meta.recruitment_agent ?? DEFAULT_RECRUITMENT_AGENT)
  }, [isResponded, meta, roles])

  useEffect(() => {
    setRecruitmentAgent(meta.recruitment_agent ?? DEFAULT_RECRUITMENT_AGENT)
  }, [meta.recruitment_agent])

  const buildReplyMetadata = useCallback((action: 'manual_approve' | 'auto_recruit'): CheckpointReplyMetadata => {
    const checkpointId = String(meta.checkpoint_id ?? '').trim()
    if (!checkpointId) {
      throw new Error('Staffing checkpoint reply requires checkpoint_id metadata.')
    }
    return {
      response_to_checkpoint_id: checkpointId,
      response_to_checkpoint_type: 'company_staffing_selection',
      staffing_action: action,
      staffing_selections: selections,
      recruitment_agent: recruitmentAgent,
      recruitment_role_agents: roles.reduce<Record<string, TaskPreferredAgent>>((acc, role) => {
        const roleId = String(role.role_id ?? '').trim()
        if (!roleId) return acc
        acc[roleId] = roleAgents[roleId] ?? role.selected_agent ?? role.default_agent ?? DEFAULT_ROLE_AGENT
        return acc
      }, {}),
    }
  }, [meta.checkpoint_id, recruitmentAgent, roleAgents, roles, selections])

  const handleApprove = useCallback(() => {
    if (isResponded) return
    onReply('approve', buildReplyMetadata('manual_approve'))
  }, [buildReplyMetadata, isResponded, onReply])

  const handleAutoRecruit = useCallback(() => {
    if (isResponded) return
    onReply('auto recruit', buildReplyMetadata('auto_recruit'))
  }, [buildReplyMetadata, isResponded, onReply])

  return (
    <div className="ckpt-panel ckpt-staffing">
      <div className="ckpt-header">
        <div className="ckpt-icon ckpt-icon-staffing">
          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
            <path d="M6 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" />
            <path d="M1.5 14c.6-2.5 2.2-4 4.5-4s3.9 1.5 4.5 4" />
            <path d="M12.5 3.5v5M10 6h5" />
          </svg>
        </div>
        <div className="ckpt-title">Manual Staffing</div>
        <span className="ckpt-badge ckpt-badge-profile">{meta.company_profile || 'corporate'}</span>
        {recommendAutoRecruit && !isResponded && <span className="ckpt-badge ckpt-badge-scope">Recruit recommended</span>}
        {isResponded && <span className="ckpt-badge ckpt-badge-responded">Responded</span>}
      </div>

      {meta.summary && <div className="ckpt-summary">{meta.summary}</div>}

      <div className="ckpt-recruiter-agent">
        <label className="ckpt-agent-label" htmlFor={`staffing-recruiter-agent-${meta.checkpoint_id}`}>
          Recruiter Agent
        </label>
        <select
          id={`staffing-recruiter-agent-${meta.checkpoint_id}`}
          className="ckpt-agent-select"
          value={recruitmentAgent}
          onChange={event => setRecruitmentAgent(event.target.value as TaskPreferredAgent)}
          disabled={isResponded}
        >
          {RECRUITMENT_AGENT_OPTIONS.map(agent => (
            <option key={agent} value={agent}>{TASK_AGENT_LABELS[agent]}</option>
          ))}
        </select>
      </div>

      <div className="ckpt-staffing-grid">
        {roles.map(role => {
          const roleId = String(role.role_id ?? '').trim()
          const options = optionsByRole[roleId] ?? [{ kind: 'fallback', id: '', name: 'Fallback role-only', subtitle: 'No employee override', category: 'fallback', searchText: 'fallback role only no employee override' }]
          const selected = optionForSelection(options, selections[roleId])
          const query = queries[roleId] ?? ''
          const visibleOptions = options.filter(option => optionMatches(option, query)).slice(0, 8)
          return (
            <div key={roleId} className="ckpt-staffing-card">
              <div className="ckpt-proposal-header">
                <span className="ckpt-role-name">{roleId}</span>
                <span className={`ckpt-badge ckpt-badge-${selected.kind}`}>{selected.kind}</span>
              </div>
              {role.role_label && role.role_label !== roleId && (
                <div className="ckpt-role-labels">
                  <span className="ckpt-field-tag">{role.role_label}</span>
                </div>
              )}
              <div className="ckpt-staffing-selected">
                <div className="ckpt-cand-name">{selected.name}</div>
                <div className="ckpt-cand-meta">
                  <span className="ckpt-cand-category">{selected.category}</span>
                  <span className="ckpt-domain-tag">{selected.subtitle}</span>
                </div>
              </div>
              <input
                className="ckpt-staffing-search"
                value={query}
                onChange={event => setQueries(current => ({ ...current, [roleId]: event.target.value }))}
                placeholder="Search employees or templates..."
                disabled={isResponded}
              />
              <div className="ckpt-staffing-options">
                {visibleOptions.map(option => {
                  const active = `${option.kind}:${option.id}` === selectionKey(selections[roleId])
                  return (
                    <button
                      key={`${option.kind}:${option.id}`}
                      className={`ckpt-staffing-option${active ? ' active' : ''}`}
                      onClick={() => setSelections(current => ({ ...current, [roleId]: { kind: option.kind, id: option.id } }))}
                      disabled={isResponded}
                      title={option.subtitle}
                    >
                      <span className="ckpt-staffing-option-kind">{option.kind}</span>
                      <span className="ckpt-staffing-option-name">{option.name}</span>
                    </button>
                  )
                })}
              </div>
              <div className="ckpt-agent-picker">
                <label className="ckpt-agent-label" htmlFor={`staffing-agent-${meta.checkpoint_id}-${roleId}`}>
                  Execution Agent
                </label>
                <select
                  id={`staffing-agent-${meta.checkpoint_id}-${roleId}`}
                  className="ckpt-agent-select"
                  value={roleAgents[roleId] ?? role.selected_agent ?? role.default_agent ?? DEFAULT_ROLE_AGENT}
                  onChange={event => setRoleAgents(current => ({ ...current, [roleId]: event.target.value as TaskPreferredAgent }))}
                  disabled={isResponded}
                >
                  {TASK_AGENT_OPTIONS.map(agent => (
                    <option key={agent} value={agent}>{TASK_AGENT_LABELS[agent]}</option>
                  ))}
                </select>
              </div>
            </div>
          )
        })}
      </div>

      {!isResponded && (
        <div className="ckpt-actions">
          {recommendAutoRecruit ? (
            <>
              <button className="ckpt-btn ckpt-btn-approve" onClick={handleAutoRecruit}>Auto Recruit</button>
              <button className="ckpt-btn ckpt-btn-feedback" onClick={handleApprove}>Approve Selections</button>
            </>
          ) : (
            <>
              <button className="ckpt-btn ckpt-btn-approve" onClick={handleApprove}>Approve Selections</button>
              {templates.length > 0 && <button className="ckpt-btn ckpt-btn-feedback" onClick={handleAutoRecruit}>Auto Recruit</button>}
            </>
          )}
        </div>
      )}
    </div>
  )
})
