import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Bot, Link2, Loader2, Plus, RefreshCw, Settings2 } from 'lucide-react';
import { FeedbackState } from '@/components/common/FeedbackState';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import {
  Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import {
  AiHardwareApiError,
  bindAiHardwareDevice,
  createAiHardwareAgent,
  getAiHardwareAgentConfiguration,
  getAiHardwareAssignment,
  getAiHardwareOverview,
  recoverAiHardwareCredential,
  updateAiHardwareAgentConfiguration,
  updateAiHardwareAssignment,
  type AiHardwareAgent,
  type AiHardwareAgentConfiguration,
  type AiHardwareAgentConfigurationUpdate,
  type AiHardwareClearableField,
  type AiHardwareDevice,
  type AiHardwareOverview,
} from '@/lib/ai-hardware';

type PageState = 'loading' | 'ready' | 'disabled' | 'auth' | 'error';
type BindRetryIntent = { agentId: string; fingerprint: ArrayBuffer; operationId: string };
type ConfigDraft = {
  agent_name: string; system_prompt: string; language: string; lang_code: string;
  asr_model_id: string; vad_model_id: string; llm_model_id: string; slm_model_id: string;
  vllm_model_id: string; tts_model_id: string;
  tts_voice_id: string; tts_volume: string; tts_rate: string; tts_pitch: string;
  tts_language: string; mem_model_id: string; intent_model_id: string;
  chat_history_conf: string;
};

const nullableTextFields = [
  'system_prompt', 'language', 'lang_code', 'asr_model_id', 'vad_model_id', 'llm_model_id',
  'slm_model_id', 'vllm_model_id', 'tts_model_id', 'tts_voice_id', 'tts_language',
  'mem_model_id', 'intent_model_id',
] as const;
const nullableNumberFields = ['tts_volume', 'tts_rate', 'tts_pitch'] as const;
const shortId = (value: string) => value.length > 12 ? `${value.slice(0, 6)}…${value.slice(-4)}` : value;
const isRevisionConflict = (error: unknown) => error instanceof AiHardwareApiError
  && ['ai_hardware_revision_conflict', 'REVISION_MISMATCH', 'AI_HARDWARE_REVISION_CONFLICT'].includes(error.code);
function safeMessage(error: unknown): string {
  if (!(error instanceof AiHardwareApiError)) return '操作没有完成，请稍后重试。';
  if (isRevisionConflict(error)) return '内容已在其他位置更新，请重新核对后再保存。';
  const messages: Record<string, string> = {
    AI_HARDWARE_AUTH_REQUIRED: '请先登录 Works Square，然后重试。',
    AI_HARDWARE_FORBIDDEN: '当前账号无权执行此操作。',
    AI_HARDWARE_DISABLED: 'AI 机器模块尚未启用，请联系管理员。',
    ai_hardware_unconfigured: 'AI 机器服务尚未配置，请联系管理员。',
    ai_hardware_credential_recovery_required: '需要管理员恢复设备凭据后才能继续。',
    ai_hardware_credential_unavailable: '设备凭据暂不可用，请联系管理员恢复。',
    ai_hardware_credential_recovery_unavailable: '当前状态无需或不能恢复凭据，请刷新查看最新状态。',
    ai_hardware_activation_code_invalid: '激活码无效或已过期，请从设备上获取新激活码。',
    ai_hardware_device_already_bound: '设备已被绑定，无法重复绑定。',
    ai_hardware_idempotency_conflict: '本次输入与待重试操作不一致，请再次提交以启动新操作。',
    AI_HARDWARE_RATE_LIMITED: '请求过于频繁，请稍后重试。',
  };
  if (error.code === 'ai_hardware_operation_in_progress') {
    return error.retryAfterSeconds === null
      ? '操作仍在处理中，请稍后重试。'
      : `操作仍在处理中，请在 ${error.retryAfterSeconds} 秒后重试。`;
  }
  return messages[error.code] ?? (error.retryable ? '服务暂时不可用，请稍后重试。' : '操作没有完成，请稍后重试。');
}
const retryOperationId = (error: unknown): string | null => error instanceof AiHardwareApiError
  && (error.retryable || error.code === 'ai_hardware_operation_in_progress') ? error.operationId : null;

function draftFrom(config: AiHardwareAgentConfiguration): ConfigDraft {
  return {
    agent_name: config.name,
    system_prompt: config.system_prompt ?? '', language: config.language ?? '', lang_code: config.lang_code ?? '',
    asr_model_id: config.asr_model_id ?? '', vad_model_id: config.vad_model_id ?? '',
    llm_model_id: config.llm_model_id ?? '', slm_model_id: config.slm_model_id ?? '',
    vllm_model_id: config.vllm_model_id ?? '', tts_model_id: config.tts_model_id ?? '',
    tts_voice_id: config.tts_voice_id ?? '', tts_volume: config.tts_volume?.toString() ?? '',
    tts_rate: config.tts_rate?.toString() ?? '', tts_pitch: config.tts_pitch?.toString() ?? '',
    tts_language: config.tts_language ?? '', mem_model_id: config.mem_model_id ?? '',
    intent_model_id: config.intent_model_id ?? '',
    chat_history_conf: config.chat_history_conf?.toString() ?? '',
  };
}

function configurationUpdate(config: AiHardwareAgentConfiguration, draft: ConfigDraft): AiHardwareAgentConfigurationUpdate {
  const update: AiHardwareAgentConfigurationUpdate = {};
  const clearFields: AiHardwareClearableField[] = [];
  if (draft.agent_name.trim() !== config.name) update.agent_name = draft.agent_name.trim();
  for (const field of nullableTextFields) {
    const value = draft[field].trim();
    if (!value && config[field] !== null) clearFields.push(field);
    else if (value && value !== config[field]) update[field] = value;
  }
  for (const field of nullableNumberFields) {
    const raw = draft[field].trim();
    if (!raw && config[field] !== null) clearFields.push(field);
    else if (raw && Number(raw) !== config[field]) update[field] = Number(raw);
  }
  if (draft.chat_history_conf !== '') {
    const history = Number(draft.chat_history_conf);
    if (history !== config.chat_history_conf) update.chat_history_conf = history;
  }
  if (clearFields.length) update.clear_fields = clearFields;
  return update;
}

function replayConfigurationUpdate(
  config: AiHardwareAgentConfiguration,
  update: AiHardwareAgentConfigurationUpdate,
): ConfigDraft {
  const next = draftFrom(config);
  if (update.agent_name !== undefined) next.agent_name = update.agent_name;
  for (const field of nullableTextFields) {
    if (update[field] !== undefined) next[field] = update[field];
    if (update.clear_fields?.includes(field)) next[field] = '';
  }
  for (const field of nullableNumberFields) {
    if (update[field] !== undefined) next[field] = update[field].toString();
    if (update.clear_fields?.includes(field)) next[field] = '';
  }
  if (update.chat_history_conf !== undefined) next.chat_history_conf = update.chat_history_conf.toString();
  return next;
}

async function createBindFingerprintKey(): Promise<CryptoKey> {
  return crypto.subtle.generateKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
}

async function bindFingerprint(key: CryptoKey, activationCode: string): Promise<ArrayBuffer> {
  return crypto.subtle.sign('HMAC', key, new TextEncoder().encode(activationCode));
}

function equalFingerprint(left: ArrayBuffer, right: ArrayBuffer): boolean {
  const a = new Uint8Array(left);
  const b = new Uint8Array(right);
  if (a.length !== b.length) return false;
  let difference = 0;
  for (let index = 0; index < a.length; index += 1) difference |= a[index] ^ b[index];
  return difference === 0;
}

export function AiHardware() {
  const [pageState, setPageState] = useState<PageState>('loading');
  const [overview, setOverview] = useState<AiHardwareOverview | null>(null);
  const [selectedAgentId, setSelectedAgentId] = useState<string | null>(null);
  const [config, setConfig] = useState<AiHardwareAgentConfiguration | null>(null);
  const [configRevision, setConfigRevision] = useState<number | null>(null);
  const [configLoading, setConfigLoading] = useState(false);
  const [configLoadFailed, setConfigLoadFailed] = useState(false);
  const [configReloadKey, setConfigReloadKey] = useState(0);
  const [notice, setNotice] = useState<string | null>(null);
  const [createOpen, setCreateOpen] = useState(false);
  const [bindOpen, setBindOpen] = useState(false);
  const [configOpen, setConfigOpen] = useState(false);
  const [assignmentDevice, setAssignmentDevice] = useState<AiHardwareDevice | null>(null);
  const [agentName, setAgentName] = useState('');
  const [dialogAgentId, setDialogAgentId] = useState('');
  const [draft, setDraft] = useState<ConfigDraft | null>(null);
  const [dialogError, setDialogError] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);
  const [createOperationId, setCreateOperationId] = useState<string | null>(null);
  const [configOperationId, setConfigOperationId] = useState<string | null>(null);
  const [assignmentOperationId, setAssignmentOperationId] = useState<string | null>(null);
  const [createOperationBody, setCreateOperationBody] = useState<string | null>(null);
  const [configOperationBody, setConfigOperationBody] = useState<string | null>(null);
  const [assignmentOperationBody, setAssignmentOperationBody] = useState<string | null>(null);
  const [recoveryOperationId, setRecoveryOperationId] = useState<string | null>(null);
  const [recoveryError, setRecoveryError] = useState<string | null>(null);
  const [recoveryBusy, setRecoveryBusy] = useState(false);
  const activationCodeInputRef = useRef<HTMLInputElement | null>(null);
  const bindFingerprintKeyRef = useRef<CryptoKey | null>(null);
  const bindRetryIntentRef = useRef<BindRetryIntent | null>(null);

  const clearCreateOperation = () => { setCreateOperationId(null); setCreateOperationBody(null); };
  const clearBindOperation = () => {
    bindRetryIntentRef.current = null;
    bindFingerprintKeyRef.current = null;
    if (activationCodeInputRef.current) activationCodeInputRef.current.value = '';
  };
  const clearConfigOperation = () => { setConfigOperationId(null); setConfigOperationBody(null); };
  const clearAssignmentOperation = () => { setAssignmentOperationId(null); setAssignmentOperationBody(null); };

  const recoverCredential = async () => {
    if (recoveryBusy) return;
    setRecoveryBusy(true); setRecoveryError(null);
    try {
      const value = recoveryOperationId
        ? await recoverAiHardwareCredential({ operationId: recoveryOperationId })
        : await recoverAiHardwareCredential();
      setRecoveryOperationId(null); setOverview(value); setPageState('ready');
      setSelectedAgentId(value.agents[0]?.id ?? null);
    } catch (error) {
      if (error instanceof AiHardwareApiError && error.code === 'ai_hardware_credential_recovery_unavailable') {
        setRecoveryOperationId(null);
        await loadOverview();
        return;
      }
      setRecoveryOperationId(retryOperationId(error));
      setRecoveryError(safeMessage(error));
    } finally { setRecoveryBusy(false); }
  };

  const loadOverview = useCallback(async () => {
    setPageState('loading'); setNotice(null);
    try {
      const value = await getAiHardwareOverview();
      setOverview(value); setPageState('ready');
      setSelectedAgentId((current) => value.agents.some((item) => item.id === current) ? current : value.agents[0]?.id ?? null);
    } catch (error) {
      setOverview(null);
      if (error instanceof AiHardwareApiError && error.code === 'AI_HARDWARE_AUTH_REQUIRED') setPageState('auth');
      else if (error instanceof AiHardwareApiError && ['AI_HARDWARE_DISABLED', 'ai_hardware_unconfigured'].includes(error.code)) setPageState('disabled');
      else setPageState('error');
    }
  }, []);

  useEffect(() => { void loadOverview(); }, [loadOverview]);
  useEffect(() => {
    if (!selectedAgentId) {
      setConfig(null);
      setConfigRevision(null);
      setConfigLoading(false);
      setConfigLoadFailed(false);
      return;
    }
    let active = true;
    setConfig(null);
    setConfigRevision(null);
    setConfigLoadFailed(false);
    setNotice(null);
    setConfigLoading(true);
    void getAiHardwareAgentConfiguration(selectedAgentId).then((result) => {
      if (!active) return;
      setConfig(result.data); setConfigRevision(result.revision);
    }).catch(() => {
      if (!active) return;
      setConfigLoadFailed(true);
      setNotice('无法读取智能体配置，请刷新后重试。');
    })
      .finally(() => { if (active) setConfigLoading(false); });
    return () => { active = false; };
  }, [configReloadKey, selectedAgentId]);

  const selectedAgent = overview?.agents.find((item) => item.id === selectedAgentId) ?? null;
  const devices = useMemo(() => overview?.devices ?? [], [overview]);
  const resetDialog = () => {
    setDialogError(null); setBusy(false);
    clearCreateOperation(); clearBindOperation(); clearConfigOperation(); clearAssignmentOperation();
  };

  const createAgent = async () => {
    const name = agentName.trim();
    if (!name || name.length > 64) { setDialogError('名称需要包含 1–64 个字符。'); return; }
    setBusy(true); setDialogError(null);
    try {
      const canRetry = createOperationId && createOperationBody === name;
      const agent = canRetry ? await createAiHardwareAgent(name, { operationId: createOperationId }) : await createAiHardwareAgent(name);
      setCreateOperationId(null);
      setCreateOperationBody(null);
      setCreateOpen(false); setAgentName(''); await loadOverview(); setSelectedAgentId(agent.id);
    } catch (error) { setCreateOperationId(retryOperationId(error)); setCreateOperationBody(name); setDialogError(safeMessage(error)); } finally { setBusy(false); }
  };

  const bindDevice = async () => {
    const activationCode = activationCodeInputRef.current?.value ?? '';
    if (!/^[0-9]{6}$/.test(activationCode)) { setDialogError('请输入 6 位数字激活码。'); return; }
    if (!dialogAgentId) { setDialogError('请选择要绑定的智能体。'); return; }
    setBusy(true); setDialogError(null);
    try {
      const key = bindFingerprintKeyRef.current ?? await createBindFingerprintKey();
      bindFingerprintKeyRef.current = key;
      const fingerprint = await bindFingerprint(key, activationCode);
      const retry = bindRetryIntentRef.current;
      if (retry?.agentId === dialogAgentId && equalFingerprint(retry.fingerprint, fingerprint)) {
        await bindAiHardwareDevice(activationCode, dialogAgentId, { operationId: retry.operationId });
      }
      else await bindAiHardwareDevice(activationCode, dialogAgentId);
      clearBindOperation();
      setBindOpen(false); await loadOverview();
    } catch (error) {
      const operationId = retryOperationId(error);
      if (operationId && bindFingerprintKeyRef.current) {
        bindRetryIntentRef.current = {
          agentId: dialogAgentId,
          fingerprint: await bindFingerprint(bindFingerprintKeyRef.current, activationCode),
          operationId,
        };
      } else bindRetryIntentRef.current = null;
      setDialogError(safeMessage(error));
      if (activationCodeInputRef.current) activationCodeInputRef.current.value = '';
    } finally { setBusy(false); }
  };

  const saveConfiguration = async () => {
    if (!config || !draft || configRevision === null) return;
    if (!draft.agent_name.trim() || draft.agent_name.trim().length > 64) { setDialogError('名称需要包含 1–64 个字符。'); return; }
    for (const field of nullableNumberFields) {
      if (draft[field] && (!Number.isInteger(Number(draft[field])) || Number(draft[field]) < -100 || Number(draft[field]) > 100)) {
        setDialogError('音量、语速和音调必须是 -100 到 100 的整数。'); return;
      }
    }
    const update = configurationUpdate(config, draft);
    if (!Object.keys(update).length) { setConfigOpen(false); return; }
    setBusy(true); setDialogError(null);
    try {
      const body = JSON.stringify(update);
      const result = configOperationId && configOperationBody === body
        ? await updateAiHardwareAgentConfiguration(config.id, configRevision, update, { operationId: configOperationId })
        : await updateAiHardwareAgentConfiguration(config.id, configRevision, update);
      setConfigOperationId(null);
      setConfigOperationBody(null);
      setConfig(result.data); setConfigRevision(result.revision); setConfigOpen(false); await loadOverview();
    } catch (error) {
      if (isRevisionConflict(error)) {
        setConfigOperationId(null);
        const fresh = await getAiHardwareAgentConfiguration(config.id).catch(() => null);
        if (fresh) {
          setConfig(fresh.data);
          setConfigRevision(fresh.revision);
          setDraft(replayConfigurationUpdate(fresh.data, update));
        }
      }
      else { setConfigOperationId(retryOperationId(error)); setConfigOperationBody(JSON.stringify(update)); }
      setDialogError(safeMessage(error));
    } finally { setBusy(false); }
  };

  const openAssignment = async (device: AiHardwareDevice) => {
    setDialogError(null); setBusy(true); setDialogAgentId(device.agent_id); setAssignmentOperationId(null);
    try { const result = await getAiHardwareAssignment(device.id); setAssignmentDevice({ ...result.data, assignment_revision: result.revision }); }
    catch { setNotice('无法读取设备指派，请刷新后重试。'); }
    finally { setBusy(false); }
  };
  const saveAssignment = async () => {
    if (!assignmentDevice || !dialogAgentId) return;
    setBusy(true); setDialogError(null);
    try {
      const body = dialogAgentId;
      if (assignmentOperationId && assignmentOperationBody === body) await updateAiHardwareAssignment(assignmentDevice.id, assignmentDevice.assignment_revision, dialogAgentId, { operationId: assignmentOperationId });
      else await updateAiHardwareAssignment(assignmentDevice.id, assignmentDevice.assignment_revision, dialogAgentId);
      setAssignmentOperationId(null);
      setAssignmentOperationBody(null);
      setAssignmentDevice(null); await loadOverview();
    } catch (error) {
      if (isRevisionConflict(error)) {
        setAssignmentOperationId(null);
        const fresh = await getAiHardwareAssignment(assignmentDevice.id).catch(() => null);
        if (fresh) setAssignmentDevice({ ...fresh.data, assignment_revision: fresh.revision });
      }
      else { setAssignmentOperationId(retryOperationId(error)); setAssignmentOperationBody(dialogAgentId); }
      setDialogError(safeMessage(error));
    } finally { setBusy(false); }
  };

  if (pageState === 'loading') return <main data-testid="ai-hardware-page" role="status" aria-live="polite" className="flex min-h-full items-center justify-center"><FeedbackState state="loading" title="正在读取 AI 机器" description="正在同步智能体与机器人设备状态。" /></main>;
  if (pageState === 'auth') return <main data-testid="ai-hardware-page" role="alert" className="flex min-h-full items-center justify-center"><FeedbackState state="error" title="请先登录 Works Square" description="登录后即可管理机器人智能体和设备。" action={<Button variant="outline" onClick={() => void loadOverview()}>重新检查</Button>} /></main>;
  if (pageState === 'disabled') return <main data-testid="ai-hardware-page" className="flex min-h-full items-center justify-center"><Card className="max-w-md"><CardHeader><CardTitle>AI 机器尚未启用</CardTitle><CardDescription>管理员启用并完成连接配置后，这里会显示你的智能体和机器人设备。</CardDescription></CardHeader><CardContent><Button variant="outline" onClick={() => void loadOverview()}><RefreshCw className="mr-2 h-4 w-4" />重新检查</Button></CardContent></Card></main>;
  if (pageState === 'error' || !overview) return <main data-testid="ai-hardware-page" role="alert" className="flex min-h-full items-center justify-center"><FeedbackState state="error" title="暂时无法读取 AI 机器" description="连接没有成功，请稍后重试。" action={<Button variant="outline" onClick={() => void loadOverview()}>重试</Button>} /></main>;
  if (overview.status === 'credential_recovery_required' || overview.status === 'invalid') return <main data-testid="ai-hardware-page" role="alert" className="flex min-h-full items-center justify-center"><div className="space-y-3 text-center"><FeedbackState state="error" title="需要恢复设备凭据" description="可在此安全地重新签发设备凭据；凭据内容不会显示在客户端。" action={<Button variant="outline" aria-busy={recoveryBusy} disabled={recoveryBusy} onClick={() => void recoverCredential()}>{recoveryBusy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}恢复设备凭据</Button>} />{recoveryError ? <p className="text-sm text-destructive">{recoveryError}</p> : null}</div></main>;
  if (overview.status === 'provisioning') return <main data-testid="ai-hardware-page" className="flex min-h-full items-center justify-center"><FeedbackState state="empty" title="正在准备机器人工作台" description="完成开通后即可创建智能体并绑定机器人设备。" action={<Button variant="outline" onClick={() => void loadOverview()}>刷新状态</Button>} /></main>;

  return (
    <main data-testid="ai-hardware-page" className="-m-5 min-h-full bg-background p-5 text-foreground sm:-m-6 sm:p-6">
      <header className="mb-6 flex flex-wrap items-start justify-between gap-4">
        <div><h1 className="text-balance text-2xl font-semibold">机器人工作台</h1><p className="mt-1 text-pretty text-sm text-muted-foreground">管理智能体、机器人设备绑定与公开配置。</p></div>
        <Button aria-label="刷新 AI 机器" variant="outline" onClick={() => void loadOverview()}><RefreshCw className="mr-2 h-4 w-4" />刷新</Button>
      </header>
      {notice ? <p role="alert" className="mb-4 rounded-xl bg-amber-500/10 px-4 py-3 text-sm font-medium text-amber-800">{notice}</p> : null}
      {overview.agents.length === 0 ? (
        <Card className="mx-auto max-w-md text-center"><CardHeader><CardTitle>创建第一个智能体</CardTitle><CardDescription>{overview.status === 'unprovisioned' ? '创建智能体将同时开通你的机器人工作台。' : '智能体创建后，才能把机器人设备绑定给它。'}</CardDescription></CardHeader><CardContent><Button onClick={() => { resetDialog(); setCreateOpen(true); }}><Plus className="mr-2 h-4 w-4" />创建智能体</Button></CardContent></Card>
      ) : (
        <div className="grid gap-5 lg:grid-cols-[minmax(240px,0.7fr)_minmax(0,1.3fr)]">
          <Card><CardHeader className="flex-row items-center justify-between"><div><CardTitle>智能体</CardTitle><CardDescription>{overview.agents.length} 个</CardDescription></div><Button size="icon" aria-label="创建智能体" onClick={() => { resetDialog(); setCreateOpen(true); }}><Plus className="h-4 w-4" /></Button></CardHeader><CardContent className="space-y-2">{overview.agents.map((agent) => <button key={agent.id} type="button" aria-pressed={agent.id === selectedAgentId} onClick={() => setSelectedAgentId(agent.id)} className={`motion-press flex min-h-12 w-full items-center gap-3 rounded-xl px-3 py-2 text-left ${agent.id === selectedAgentId ? 'bg-brand-soft' : 'bg-surface-subtle hover:bg-surface-tertiary'}`}><Bot className="h-4 w-4 shrink-0" /><span className="min-w-0 flex-1"><span className="block truncate text-sm font-semibold">{agent.name}</span><span title={agent.id} className="block text-xs tabular-nums text-muted-foreground">{shortId(agent.id)} · r{agent.config_revision}</span></span></button>)}</CardContent></Card>
          <div className="space-y-5">
            <Card><CardHeader className="flex-row items-center justify-between"><div><CardTitle>{selectedAgent?.name ?? '智能体配置'}</CardTitle><CardDescription>基础对话和语音设置</CardDescription></div><Button variant="outline" disabled={configLoading || !config} onClick={() => { if (!config) return; resetDialog(); setDraft(draftFrom(config)); setConfigOpen(true); }}>{configLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Settings2 className="mr-2 h-4 w-4" />}编辑配置</Button></CardHeader><CardContent>{config ? <dl className="grid gap-3 text-sm sm:grid-cols-2"><div><dt className="text-muted-foreground">语言</dt><dd>{config.language || config.lang_code || '未设置'}</dd></div><div><dt className="text-muted-foreground">语音</dt><dd>{config.tts_voice_id || '未设置'}</dd></div><div className="sm:col-span-2"><dt className="text-muted-foreground">系统提示</dt><dd className="mt-1 whitespace-pre-wrap">{config.system_prompt || '未设置'}</dd></div></dl> : configLoading ? <FeedbackState state="loading" title="正在读取配置" /> : configLoadFailed ? <FeedbackState state="error" title="无法读取智能体配置" description="请检查服务连接后重试。" action={<Button variant="outline" onClick={() => setConfigReloadKey((value) => value + 1)}>重试读取配置</Button>} /> : null}</CardContent></Card>
            <Card><CardHeader className="flex-row items-center justify-between"><div><CardTitle>设备</CardTitle><CardDescription>{devices.length} 台已绑定设备</CardDescription></div><Button onClick={() => { resetDialog(); setDialogAgentId(selectedAgentId ?? overview.agents[0].id); setBindOpen(true); }}><Link2 className="mr-2 h-4 w-4" />绑定设备</Button></CardHeader><CardContent>{devices.length ? <div className="space-y-2">{devices.map((device) => <div key={device.id} className="flex min-h-12 items-center justify-between gap-3 rounded-xl bg-surface-subtle px-3 py-2"><span className="min-w-0"><span className="block text-sm font-semibold">设备 {shortId(device.id)}</span><span title={device.id} className="text-xs tabular-nums text-muted-foreground">指派 r{device.assignment_revision}</span></span><Button variant="outline" size="sm" onClick={() => void openAssignment(device)}>重新指派</Button></div>)}</div> : <FeedbackState state="empty" title="还没有绑定设备" description="使用设备上的 6 位激活码完成绑定。" />}</CardContent></Card>
          </div>
        </div>
      )}

      <Dialog open={createOpen} onOpenChange={(open) => { if (!busy) { setCreateOpen(open); if (!open) { setAgentName(''); resetDialog(); } } }}><DialogContent><DialogHeader><DialogTitle>创建智能体</DialogTitle><DialogDescription>输入一个容易识别的名称，稍后仍可修改。</DialogDescription></DialogHeader><div><Label htmlFor="hardware-agent-name">名称</Label><Input id="hardware-agent-name" autoFocus maxLength={64} value={agentName} onChange={(e) => { setAgentName(e.target.value); clearCreateOperation(); }} /></div>{dialogError ? <p role="alert" className="text-sm text-destructive">{dialogError}</p> : null}<DialogFooter><Button variant="outline" disabled={busy} onClick={() => { setCreateOpen(false); resetDialog(); }}>取消</Button><Button aria-busy={busy} disabled={busy} onClick={() => void createAgent()}>{busy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}创建</Button></DialogFooter></DialogContent></Dialog>
      <Dialog open={bindOpen} onOpenChange={(open) => { if (!busy) { setBindOpen(open); if (!open) resetDialog(); } }}><DialogContent><DialogHeader><DialogTitle>绑定设备</DialogTitle><DialogDescription>激活码只用于本次绑定，关闭窗口后会立即清除。</DialogDescription></DialogHeader><div><Label htmlFor="hardware-activation-code">6 位激活码</Label><Input ref={activationCodeInputRef} id="hardware-activation-code" autoFocus type="text" inputMode="numeric" autoComplete="off" maxLength={6} onInput={(e) => { e.currentTarget.value = e.currentTarget.value.replace(/\D/g, '').slice(0, 6); }} /></div><AgentSelect agents={overview.agents} value={dialogAgentId} onChange={(value) => { setDialogAgentId(value); clearBindOperation(); }} />{dialogError ? <p role="alert" className="text-sm text-destructive">{dialogError}</p> : null}<DialogFooter><Button variant="outline" disabled={busy} onClick={() => { setBindOpen(false); resetDialog(); }}>取消</Button><Button aria-busy={busy} disabled={busy} onClick={() => void bindDevice()}>{busy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}绑定</Button></DialogFooter></DialogContent></Dialog>
      <Dialog open={configOpen} onOpenChange={(open) => { if (!busy) { setConfigOpen(open); if (!open) resetDialog(); } }}><DialogContent className="max-h-[90vh] overflow-y-auto"><DialogHeader><DialogTitle>编辑智能体配置</DialogTitle><DialogDescription>留空可清除可选字段；保存时不会发送空值。</DialogDescription></DialogHeader>{draft ? <ConfigFields draft={draft} setDraft={(next) => { setDraft(next); clearConfigOperation(); }} /> : null}{dialogError ? <p role="alert" className="text-sm text-destructive">{dialogError}</p> : null}<DialogFooter><Button variant="outline" disabled={busy} onClick={() => { setConfigOpen(false); resetDialog(); }}>取消</Button><Button aria-busy={busy} disabled={busy} onClick={() => void saveConfiguration()}>{busy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}保存</Button></DialogFooter></DialogContent></Dialog>
      <Dialog open={Boolean(assignmentDevice)} onOpenChange={(open) => { if (!open && !busy) { setAssignmentDevice(null); resetDialog(); } }}><DialogContent><DialogHeader><DialogTitle>重新指派设备</DialogTitle><DialogDescription>选择接收这台设备的智能体。系统会检查最新修订，避免覆盖其他更改。</DialogDescription></DialogHeader><AgentSelect agents={overview.agents} value={dialogAgentId} onChange={(value) => { setDialogAgentId(value); clearAssignmentOperation(); }} />{dialogError ? <p role="alert" className="text-sm text-destructive">{dialogError}</p> : null}<DialogFooter><Button variant="outline" disabled={busy} onClick={() => { setAssignmentDevice(null); resetDialog(); }}>取消</Button><Button aria-busy={busy} disabled={busy} onClick={() => void saveAssignment()}>{busy && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}确认指派</Button></DialogFooter></DialogContent></Dialog>
    </main>
  );
}

function AgentSelect({ agents, value, onChange }: { agents: AiHardwareAgent[]; value: string; onChange: (value: string) => void }) {
  return <div><Label htmlFor="hardware-agent-select">智能体</Label><select id="hardware-agent-select" className="mt-1 h-10 w-full rounded-xl border border-border/80 bg-surface-input px-3 text-sm" value={value} onChange={(e) => onChange(e.target.value)}>{agents.map((agent) => <option key={agent.id} value={agent.id}>{agent.name}</option>)}</select></div>;
}

function ConfigFields({ draft, setDraft }: { draft: ConfigDraft; setDraft: (draft: ConfigDraft) => void }) {
  const field = (key: keyof ConfigDraft, label: string, type = 'text') => <div><Label htmlFor={`hardware-${key}`}>{label}</Label><Input id={`hardware-${key}`} type={type} value={draft[key]} onChange={(e) => setDraft({ ...draft, [key]: e.target.value })} /></div>;
  return <div className="space-y-4"><div className="grid gap-4 sm:grid-cols-2">{field('agent_name', '名称')}<div className="sm:col-span-2"><Label htmlFor="hardware-system_prompt">系统提示</Label><Textarea id="hardware-system_prompt" value={draft.system_prompt} onChange={(e) => setDraft({ ...draft, system_prompt: e.target.value })} /></div>{field('language', '语言')}{field('lang_code', '语言代码')}{field('tts_voice_id', 'TTS 语音 ID')}{field('tts_volume', '音量 (-100–100)', 'number')}{field('tts_rate', '语速 (-100–100)', 'number')}{field('tts_pitch', '音调 (-100–100)', 'number')}<div><Label htmlFor="hardware-chat_history_conf">聊天记录</Label><select id="hardware-chat_history_conf" className="mt-1 h-10 w-full rounded-xl border border-border/80 bg-surface-input px-3 text-sm" value={draft.chat_history_conf} onChange={(e) => setDraft({ ...draft, chat_history_conf: e.target.value })}><option value="">未设置（保持不变）</option><option value="0">关闭</option><option value="1">摘要</option><option value="2">完整</option></select></div></div><details className="rounded-xl border border-border/80 bg-surface-subtle px-4 py-3"><summary className="cursor-pointer text-sm font-semibold">高级设置</summary><p className="mt-2 text-xs text-muted-foreground">模型 ID 由服务管理员提供；留空可清除现有设置。</p><div className="mt-4 grid gap-4 sm:grid-cols-2">{field('asr_model_id', 'ASR 模型 ID')}{field('vad_model_id', 'VAD 模型 ID')}{field('llm_model_id', 'LLM 模型 ID')}{field('slm_model_id', 'SLM 模型 ID')}{field('vllm_model_id', 'VLLM 模型 ID')}{field('tts_model_id', 'TTS 模型 ID')}{field('tts_language', 'TTS 语言')}{field('mem_model_id', '记忆模型 ID')}{field('intent_model_id', '意图模型 ID')}</div></details></div>;
}

export default AiHardware;
