import { ChevronDown, ChevronUp, ExternalLink, Plus, RefreshCw, Save, Trash2, X } from 'lucide-react';
import type { RefObject } from 'react';

import { DrawerShell } from '../../../components/DrawerShell';
import { PasswordInput } from '../../../components/PasswordInput';
import { LucentIconButton } from '../../../components/lucent/LucentIconButton';
import type { BotChannel, BotTopic, ChannelType, TopicPresetTemplate, WeixinLoginStatus } from '../types';
import './DashboardManagementModals.css';

interface PasswordToggleLabels {
  show: string;
  hide: string;
}

function parseChannelListValue(raw: unknown): string {
  if (!Array.isArray(raw)) return '';
  return raw
    .map((item) => String(item || '').trim())
    .filter(Boolean)
    .join('\n');
}

function parseChannelListInput(raw: string): string[] {
  const rows: string[] = [];
  String(raw || '')
    .split(/[\n,]/)
    .forEach((item) => {
      const text = String(item || '').trim();
      if (text && !rows.includes(text)) rows.push(text);
    });
  return rows;
}

function isChannelConfigured(channel: BotChannel): boolean {
  const ctype = String(channel.channel_type || '').trim().toLowerCase();
  if (ctype === 'email') {
    const extra = channel.extra_config || {};
    return Boolean(
      String(extra.imapHost || '').trim()
        && String(extra.imapUsername || '').trim()
        && String(extra.imapPassword || '').trim()
        && String(extra.smtpHost || '').trim()
        && String(extra.smtpUsername || '').trim()
        && String(extra.smtpPassword || '').trim(),
    );
  }
  if (ctype === 'weixin') {
    return true;
  }
  return Boolean(String(channel.external_app_id || '').trim() || String(channel.app_secret || '').trim());
}

function ChannelFieldsEditor({
  channel,
  labels,
  passwordToggleLabels,
  onPatch,
}: {
  channel: BotChannel;
  labels: Record<string, any>;
  passwordToggleLabels: PasswordToggleLabels;
  onPatch: (patch: Partial<BotChannel>) => void;
}) {
  const ctype = String(channel.channel_type).toLowerCase();
  if (ctype === 'telegram') {
    return (
      <>
        <PasswordInput className="input" placeholder={labels.telegramToken} value={channel.app_secret || ''} onChange={(e) => onPatch({ app_secret: e.target.value })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
        <input
          className="input"
          placeholder={labels.proxy}
          value={String((channel.extra_config || {}).proxy || '')}
          onChange={(e) => onPatch({ extra_config: { ...(channel.extra_config || {}), proxy: e.target.value } })}
          autoComplete="off"
        />
        <label className="field-label">
          <input
            type="checkbox"
            checked={Boolean((channel.extra_config || {}).replyToMessage)}
            onChange={(e) =>
              onPatch({ extra_config: { ...(channel.extra_config || {}), replyToMessage: e.target.checked } })
            }
            style={{ marginRight: 6 }}
          />
          {labels.replyToMessage}
        </label>
      </>
    );
  }

  if (ctype === 'feishu') {
    return (
      <>
        <input className="input" placeholder={labels.appId} value={channel.external_app_id || ''} onChange={(e) => onPatch({ external_app_id: e.target.value })} autoComplete="off" />
        <PasswordInput className="input" placeholder={labels.appSecret} value={channel.app_secret || ''} onChange={(e) => onPatch({ app_secret: e.target.value })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
        <input className="input" placeholder={labels.encryptKey} value={String((channel.extra_config || {}).encryptKey || '')} onChange={(e) => onPatch({ extra_config: { ...(channel.extra_config || {}), encryptKey: e.target.value } })} autoComplete="off" />
        <input className="input" placeholder={labels.verificationToken} value={String((channel.extra_config || {}).verificationToken || '')} onChange={(e) => onPatch({ extra_config: { ...(channel.extra_config || {}), verificationToken: e.target.value } })} autoComplete="off" />
      </>
    );
  }

  if (ctype === 'dingtalk') {
    return (
      <>
        <input className="input" placeholder={labels.clientId} value={channel.external_app_id || ''} onChange={(e) => onPatch({ external_app_id: e.target.value })} autoComplete="off" />
        <PasswordInput className="input" placeholder={labels.clientSecret} value={channel.app_secret || ''} onChange={(e) => onPatch({ app_secret: e.target.value })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
      </>
    );
  }

  if (ctype === 'slack') {
    return (
      <>
        <input className="input" placeholder={labels.botToken} value={channel.external_app_id || ''} onChange={(e) => onPatch({ external_app_id: e.target.value })} autoComplete="off" />
        <PasswordInput className="input" placeholder={labels.appToken} value={channel.app_secret || ''} onChange={(e) => onPatch({ app_secret: e.target.value })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
      </>
    );
  }

  if (ctype === 'qq') {
    return (
      <>
        <input className="input" placeholder={labels.appId} value={channel.external_app_id || ''} onChange={(e) => onPatch({ external_app_id: e.target.value })} autoComplete="off" />
        <PasswordInput className="input" placeholder={labels.appSecret} value={channel.app_secret || ''} onChange={(e) => onPatch({ app_secret: e.target.value })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
      </>
    );
  }

  if (ctype === 'weixin') {
    return null;
  }

  if (ctype === 'email') {
    const extra = channel.extra_config || {};
    return (
      <>
        <div className="ops-config-field" style={{ alignSelf: 'end' }}>
          <label className="field-label">
            <input
              type="checkbox"
              checked={Boolean(extra.consentGranted)}
              onChange={(e) => onPatch({ extra_config: { ...extra, consentGranted: e.target.checked } })}
              style={{ marginRight: 6 }}
            />
            {labels.emailConsentGranted}
          </label>
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailFromAddress}</label>
          <input
            className="input"
            value={String(extra.fromAddress || '')}
            onChange={(e) => onPatch({ extra_config: { ...extra, fromAddress: e.target.value } })}
            autoComplete="off"
          />
        </div>
        <div className="ops-config-field ops-config-field-full">
          <label className="field-label">{labels.emailAllowFrom}</label>
          <textarea
            className="textarea"
            rows={3}
            value={parseChannelListValue(extra.allowFrom)}
            onChange={(e) => onPatch({ extra_config: { ...extra, allowFrom: parseChannelListInput(e.target.value) } })}
            placeholder={labels.emailAllowFromPlaceholder}
          />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailImapHost}</label>
          <input className="input" value={String(extra.imapHost || '')} onChange={(e) => onPatch({ extra_config: { ...extra, imapHost: e.target.value } })} autoComplete="off" />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailImapPort}</label>
          <input className="input mono" type="number" min="1" max="65535" value={String(extra.imapPort ?? 993)} onChange={(e) => onPatch({ extra_config: { ...extra, imapPort: Number(e.target.value || 993) } })} />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailImapUsername}</label>
          <input className="input" value={String(extra.imapUsername || '')} onChange={(e) => onPatch({ extra_config: { ...extra, imapUsername: e.target.value } })} autoComplete="username" />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailImapPassword}</label>
          <PasswordInput className="input" value={String(extra.imapPassword || '')} onChange={(e) => onPatch({ extra_config: { ...extra, imapPassword: e.target.value } })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailImapMailbox}</label>
          <input className="input" value={String(extra.imapMailbox || 'INBOX')} onChange={(e) => onPatch({ extra_config: { ...extra, imapMailbox: e.target.value } })} autoComplete="off" />
        </div>
        <div className="ops-config-field" style={{ alignSelf: 'end' }}>
          <label className="field-label">
            <input
              type="checkbox"
              checked={Boolean(extra.imapUseSsl ?? true)}
              onChange={(e) => onPatch({ extra_config: { ...extra, imapUseSsl: e.target.checked } })}
              style={{ marginRight: 6 }}
            />
            {labels.emailImapUseSsl}
          </label>
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailSmtpHost}</label>
          <input className="input" value={String(extra.smtpHost || '')} onChange={(e) => onPatch({ extra_config: { ...extra, smtpHost: e.target.value } })} autoComplete="off" />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailSmtpPort}</label>
          <input className="input mono" type="number" min="1" max="65535" value={String(extra.smtpPort ?? 587)} onChange={(e) => onPatch({ extra_config: { ...extra, smtpPort: Number(e.target.value || 587) } })} />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailSmtpUsername}</label>
          <input className="input" value={String(extra.smtpUsername || '')} onChange={(e) => onPatch({ extra_config: { ...extra, smtpUsername: e.target.value } })} autoComplete="username" />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailSmtpPassword}</label>
          <PasswordInput className="input" value={String(extra.smtpPassword || '')} onChange={(e) => onPatch({ extra_config: { ...extra, smtpPassword: e.target.value } })} autoComplete="new-password" toggleLabels={passwordToggleLabels} />
        </div>
        <div className="ops-config-field" style={{ alignSelf: 'end' }}>
          <label className="field-label">
            <input
              type="checkbox"
              checked={Boolean(extra.smtpUseTls ?? true)}
              onChange={(e) => onPatch({ extra_config: { ...extra, smtpUseTls: e.target.checked } })}
              style={{ marginRight: 6 }}
            />
            {labels.emailSmtpUseTls}
          </label>
        </div>
        <div className="ops-config-field" style={{ alignSelf: 'end' }}>
          <label className="field-label">
            <input
              type="checkbox"
              checked={Boolean(extra.smtpUseSsl)}
              onChange={(e) => onPatch({ extra_config: { ...extra, smtpUseSsl: e.target.checked } })}
              style={{ marginRight: 6 }}
            />
            {labels.emailSmtpUseSsl}
          </label>
        </div>
        <div className="ops-config-field" style={{ alignSelf: 'end' }}>
          <label className="field-label">
            <input
              type="checkbox"
              checked={Boolean(extra.autoReplyEnabled ?? true)}
              onChange={(e) => onPatch({ extra_config: { ...extra, autoReplyEnabled: e.target.checked } })}
              style={{ marginRight: 6 }}
            />
            {labels.emailAutoReplyEnabled}
          </label>
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailPollIntervalSeconds}</label>
          <input className="input mono" type="number" min="5" max="3600" value={String(extra.pollIntervalSeconds ?? 30)} onChange={(e) => onPatch({ extra_config: { ...extra, pollIntervalSeconds: Number(e.target.value || 30) } })} />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailMaxBodyChars}</label>
          <input className="input mono" type="number" min="1" max="50000" value={String(extra.maxBodyChars ?? 12000)} onChange={(e) => onPatch({ extra_config: { ...extra, maxBodyChars: Number(e.target.value || 12000) } })} />
        </div>
        <div className="ops-config-field">
          <label className="field-label">{labels.emailSubjectPrefix}</label>
          <input className="input" value={String(extra.subjectPrefix || 'Re: ')} onChange={(e) => onPatch({ extra_config: { ...extra, subjectPrefix: e.target.value } })} autoComplete="off" />
        </div>
        <div className="ops-config-field" style={{ alignSelf: 'end' }}>
          <label className="field-label">
            <input
              type="checkbox"
              checked={Boolean(extra.markSeen ?? true)}
              onChange={(e) => onPatch({ extra_config: { ...extra, markSeen: e.target.checked } })}
              style={{ marginRight: 6 }}
            />
            {labels.emailMarkSeen}
          </label>
        </div>
      </>
    );
  }

  return null;
}

interface ChannelConfigModalProps {
  open: boolean;
  channels: BotChannel[];
  globalDelivery: { sendProgress: boolean; sendToolHints: boolean };
  expandedChannelByKey: Record<string, boolean>;
  newChannelDraft: BotChannel;
  addableChannelTypes: ChannelType[];
  newChannelPanelOpen: boolean;
  channelCreateMenuOpen: boolean;
  channelCreateMenuRef: RefObject<HTMLDivElement | null>;
  isSavingGlobalDelivery: boolean;
  isSavingChannel: boolean;
  weixinLoginStatus: WeixinLoginStatus | null;
  hasSelectedBot: boolean;
  isZh: boolean;
  labels: Record<string, any>;
  passwordToggleLabels: PasswordToggleLabels;
  onClose: () => void;
  onUpdateGlobalDeliveryFlag: (key: 'sendProgress' | 'sendToolHints', value: boolean) => void;
  onSaveGlobalDelivery: () => Promise<void> | void;
  getChannelUiKey: (channel: Pick<BotChannel, 'id' | 'channel_type'>, fallbackIndex: number) => string;
  isDashboardChannel: (channel: BotChannel) => boolean;
  onUpdateChannelLocal: (index: number, patch: Partial<BotChannel>) => void;
  onToggleExpandedChannel: (key: string) => void;
  onRemoveChannel: (channel: BotChannel) => Promise<void> | void;
  onSaveChannel: (channel: BotChannel) => Promise<void> | void;
  onReloginWeixin: () => Promise<void> | void;
  onSetNewChannelPanelOpen: (value: boolean) => void;
  onSetChannelCreateMenuOpen: (value: boolean | ((prev: boolean) => boolean)) => void;
  onResetNewChannelDraft: (channelType?: ChannelType) => void;
  onUpdateNewChannelDraft: (patch: Partial<BotChannel>) => void;
  onBeginChannelCreate: (channelType: ChannelType) => void;
  onAddChannel: () => Promise<void> | void;
}

export function ChannelConfigModal({
  open,
  channels,
  globalDelivery,
  expandedChannelByKey,
  newChannelDraft,
  addableChannelTypes,
  newChannelPanelOpen,
  channelCreateMenuOpen,
  channelCreateMenuRef,
  isSavingGlobalDelivery,
  isSavingChannel,
  weixinLoginStatus,
  hasSelectedBot,
  isZh,
  labels,
  passwordToggleLabels,
  onClose,
  onUpdateGlobalDeliveryFlag,
  onSaveGlobalDelivery,
  getChannelUiKey,
  isDashboardChannel,
  onUpdateChannelLocal,
  onToggleExpandedChannel,
  onRemoveChannel,
  onSaveChannel,
  onReloginWeixin,
  onSetNewChannelPanelOpen,
  onSetChannelCreateMenuOpen,
  onResetNewChannelDraft,
  onUpdateNewChannelDraft,
  onBeginChannelCreate,
  onAddChannel,
}: ChannelConfigModalProps) {
  if (!open) return null;

  const renderWeixinLoginBlock = (channel: BotChannel) => {
    const channelType = String(channel.channel_type || '').trim().toLowerCase();
    if (String(channelType || '').trim().toLowerCase() !== 'weixin') return null;

    const loginUrl = String(weixinLoginStatus?.login_url || '').trim();

    return (
      <div className="ops-config-weixin-login">
        <div className="ops-config-weixin-actions">
          <button
            className="btn btn-primary btn-sm"
            disabled={isSavingChannel}
            onClick={() => void onReloginWeixin()}
          >
            {labels.weixinRelogin}
          </button>
        </div>
        <div className="ops-config-weixin-login-hint">{labels.weixinLoginHint}</div>
        {loginUrl ? (
          <div className="ops-config-weixin-login-body">
            <div className="ops-config-weixin-login-url mono" title={loginUrl}>{loginUrl}</div>
            <a
              className="ops-config-weixin-login-link"
              href={loginUrl}
              target="_blank"
              rel="noreferrer"
            >
              <ExternalLink size={14} />
              <span>{labels.weixinLoginOpen}</span>
            </a>
          </div>
        ) : null}
      </div>
    );
  };

  return (
    <DrawerShell
      open={open}
      onClose={onClose}
      title={labels.wizardSectionTitle}
      subtitle={labels.wizardSectionDesc}
      size="extend"
      closeLabel={labels.close}
      bodyClassName="ops-config-drawer-body"
      footer={(
        !newChannelPanelOpen ? (
          <div className="drawer-shell-footer-content">
            <div className="drawer-shell-footer-main field-label">{labels.channelAddHint}</div>
            <div className="ops-topic-create-menu-wrap" ref={channelCreateMenuRef}>
              <button
                className="btn btn-primary"
                disabled={addableChannelTypes.length === 0 || isSavingChannel}
                onClick={() => onSetChannelCreateMenuOpen((prev) => !prev)}
              >
                <Plus size={14} />
                <span style={{ marginLeft: 6 }}>{labels.addChannel}</span>
              </button>
              {channelCreateMenuOpen ? (
                <div className="ops-topic-create-menu">
                  {addableChannelTypes.map((channelType) => (
                    <button key={channelType} className="ops-topic-create-menu-item" onClick={() => onBeginChannelCreate(channelType)}>
                      {String(channelType || '').toUpperCase()}
                    </button>
                  ))}
                </div>
              ) : null}
            </div>
          </div>
        ) : undefined
      )}
    >
      <div className="ops-config-modal">
        <div className="card" style={{ fontSize: 12, color: 'var(--muted)' }}>
          {labels.wizardSectionDesc}
        </div>
        <div className="card">
          <div className="section-mini-title">{labels.globalDeliveryTitle}</div>
          <div className="field-label">{labels.globalDeliveryDesc}</div>
          <div className="wizard-dashboard-switches" style={{ marginTop: 8 }}>
            <label className="field-label">
              <input
                type="checkbox"
                checked={Boolean(globalDelivery.sendProgress)}
                onChange={(e) => onUpdateGlobalDeliveryFlag('sendProgress', e.target.checked)}
                style={{ marginRight: 6 }}
              />
              {labels.sendProgress}
            </label>
            <label className="field-label">
              <input
                type="checkbox"
                checked={Boolean(globalDelivery.sendToolHints)}
                onChange={(e) => onUpdateGlobalDeliveryFlag('sendToolHints', e.target.checked)}
                style={{ marginRight: 6 }}
              />
              {labels.sendToolHints}
            </label>
            <LucentIconButton
              className="btn btn-primary btn-sm icon-btn"
              disabled={isSavingGlobalDelivery || !hasSelectedBot}
              onClick={() => void onSaveGlobalDelivery()}
              tooltip={labels.saveChannel}
              aria-label={labels.saveChannel}
            >
              <Save size={14} />
            </LucentIconButton>
          </div>
        </div>
        <div className="wizard-channel-list ops-config-list-scroll">
          {channels.filter((channel) => !isDashboardChannel(channel)).length === 0 ? (
            <div className="ops-empty-inline">{labels.channelEmpty}</div>
          ) : (
            channels.map((channel, idx) => {
              if (isDashboardChannel(channel)) return null;
              const uiKey = getChannelUiKey(channel, idx);
              const expanded = expandedChannelByKey[uiKey] ?? idx === 0;
              const summary = [
                String(channel.channel_type || '').toUpperCase(),
                channel.is_active ? labels.enabled : labels.disabled,
                isChannelConfigured(channel) ? labels.channelConfigured : labels.channelPending,
              ].join(' · ');
              return (
                <div key={`${channel.id}-${channel.channel_type}`} className="card wizard-channel-card wizard-channel-compact">
                  <div className="ops-config-card-header">
                    <div className="ops-config-card-main">
                      <strong>{String(channel.channel_type || '').toUpperCase()}</strong>
                      <div className="ops-config-collapsed-meta">{summary}</div>
                    </div>
                    <div className="ops-config-card-actions">
                      <label className="field-label">
                        <input
                          type="checkbox"
                          checked={channel.is_active}
                          onChange={(e) => onUpdateChannelLocal(idx, { is_active: e.target.checked })}
                          style={{ marginRight: 6 }}
                        />
                        {labels.enabled}
                      </label>
                      <LucentIconButton
                        className="btn btn-danger btn-sm wizard-icon-btn"
                        disabled={isSavingChannel}
                        onClick={() => void onRemoveChannel(channel)}
                        tooltip={labels.remove}
                        aria-label={labels.remove}
                      >
                        <Trash2 size={14} />
                      </LucentIconButton>
                      <LucentIconButton
                        className="ops-plain-icon-btn"
                        onClick={() => onToggleExpandedChannel(uiKey)}
                        tooltip={expanded ? (isZh ? '收起详情' : 'Collapse') : (isZh ? '展开详情' : 'Expand')}
                        aria-label={expanded ? (isZh ? '收起详情' : 'Collapse') : (isZh ? '展开详情' : 'Expand')}
                      >
                        {expanded ? <ChevronUp size={14} /> : <ChevronDown size={14} />}
                      </LucentIconButton>
                    </div>
                  </div>
                  {expanded ? (
                    <>
                      <div className="ops-topic-grid">
                        <ChannelFieldsEditor
                          channel={channel}
                          labels={labels}
                          passwordToggleLabels={passwordToggleLabels}
                          onPatch={(patch) => onUpdateChannelLocal(idx, patch)}
                        />
                      </div>
                      {renderWeixinLoginBlock(channel)}
                      <div className="row-between ops-config-footer">
                        <span className="field-label">{labels.customChannel}</span>
                        <button className="btn btn-primary btn-sm" disabled={isSavingChannel} onClick={() => void onSaveChannel(channel)}>
                          <Save size={14} />
                          <span style={{ marginLeft: 6 }}>{labels.saveChannel}</span>
                        </button>
                      </div>
                    </>
                  ) : null}
                </div>
              );
            })
          )}
        </div>
        {newChannelPanelOpen ? (
          <div className="card wizard-channel-card wizard-channel-compact ops-config-new-card">
            <div className="ops-config-card-header">
              <div className="ops-config-card-main">
                <strong>{labels.addChannel}</strong>
                <div className="ops-config-collapsed-meta">{String(newChannelDraft.channel_type || '').toUpperCase()}</div>
              </div>
              <div className="ops-config-card-actions">
                <LucentIconButton
                  className="ops-plain-icon-btn"
                  onClick={() => {
                    onSetNewChannelPanelOpen(false);
                    onResetNewChannelDraft();
                  }}
                  tooltip={labels.cancel}
                  aria-label={labels.cancel}
                >
                  <X size={15} />
                </LucentIconButton>
              </div>
            </div>
            <div className="ops-topic-grid">
              <div className="ops-config-field">
                <label className="field-label">{labels.channelType}</label>
                <input className="input mono" value={String(newChannelDraft.channel_type || '').toUpperCase()} readOnly />
              </div>
              <div className="ops-config-field" style={{ alignSelf: 'end' }}>
                <label className="field-label" style={{ visibility: 'hidden' }}>{labels.enabled}</label>
                <label className="field-label">
                  <input
                    type="checkbox"
                    checked={newChannelDraft.is_active}
                    onChange={(e) => onUpdateNewChannelDraft({ is_active: e.target.checked })}
                    style={{ marginRight: 6 }}
                  />
                  {labels.enabled}
                </label>
              </div>
              <ChannelFieldsEditor
                channel={newChannelDraft}
                labels={labels}
                passwordToggleLabels={passwordToggleLabels}
                onPatch={onUpdateNewChannelDraft}
              />
            </div>
            <div className="row-between ops-config-footer">
              <span className="field-label">{labels.channelAddHint}</span>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                <button
                  className="btn btn-secondary btn-sm"
                  onClick={() => {
                    onSetNewChannelPanelOpen(false);
                    onResetNewChannelDraft();
                  }}
                >
                  {labels.cancel}
                </button>
                <button className="btn btn-primary btn-sm" disabled={isSavingChannel} onClick={() => void onAddChannel()}>
                  <Save size={14} />
                  <span style={{ marginLeft: 6 }}>{labels.saveChannel}</span>
                </button>
              </div>
            </div>
          </div>
        ) : null}
      </div>
    </DrawerShell>
  );
}

interface TopicConfigModalProps {
  open: boolean;
  topics: BotTopic[];
  expandedTopicByKey: Record<string, boolean>;
  newTopicPanelOpen: boolean;
  topicPresetMenuOpen: boolean;
  newTopicAdvancedOpen: boolean;
  newTopicSourceLabel: string;
  newTopicKey: string;
  newTopicName: string;
  newTopicDescription: string;
  newTopicPurpose: string;
  newTopicIncludeWhen: string;
  newTopicExcludeWhen: string;
  newTopicExamplesPositive: string;
  newTopicExamplesNegative: string;
  newTopicPriority: string;
  effectiveTopicPresetTemplates: TopicPresetTemplate[];
  topicPresetMenuRef: RefObject<HTMLDivElement | null>;
  isSavingTopic: boolean;
  hasSelectedBot: boolean;
  isZh: boolean;
  labels: Record<string, any>;
  onClose: () => void;
  getTopicUiKey: (topic: Pick<BotTopic, 'topic_key' | 'id'>, fallbackIndex: number) => string;
  countRoutingTextList: (raw: string) => number;
  onUpdateTopicLocal: (index: number, patch: Partial<BotTopic>) => void;
  onToggleExpandedTopic: (key: string) => void;
  onRemoveTopic: (topic: BotTopic) => Promise<void> | void;
  onSaveTopic: (topic: BotTopic) => Promise<void> | void;
  onSetNewTopicPanelOpen: (value: boolean) => void;
  onSetTopicPresetMenuOpen: (value: boolean | ((prev: boolean) => boolean)) => void;
  onSetNewTopicAdvancedOpen: (value: boolean | ((prev: boolean) => boolean)) => void;
  onResetNewTopicDraft: () => void;
  onNormalizeTopicKeyInput: (value: string) => string;
  onSetNewTopicKey: (value: string) => void;
  onSetNewTopicName: (value: string) => void;
  onSetNewTopicDescription: (value: string) => void;
  onSetNewTopicPurpose: (value: string) => void;
  onSetNewTopicIncludeWhen: (value: string) => void;
  onSetNewTopicExcludeWhen: (value: string) => void;
  onSetNewTopicExamplesPositive: (value: string) => void;
  onSetNewTopicExamplesNegative: (value: string) => void;
  onSetNewTopicPriority: (value: string) => void;
  onBeginTopicCreate: (presetId: string) => void;
  onResolvePresetLabel: (preset: TopicPresetTemplate) => string;
  onAddTopic: () => Promise<void> | void;
}

export function TopicConfigModal({
  open,
  topics,
  expandedTopicByKey,
  newTopicPanelOpen,
  topicPresetMenuOpen,
  newTopicAdvancedOpen,
  newTopicSourceLabel,
  newTopicKey,
  newTopicName,
  newTopicDescription,
  newTopicPurpose,
  newTopicIncludeWhen,
  newTopicExcludeWhen,
  newTopicExamplesPositive,
  newTopicExamplesNegative,
  newTopicPriority,
  effectiveTopicPresetTemplates,
  topicPresetMenuRef,
  isSavingTopic,
  hasSelectedBot,
  isZh,
  labels,
  onClose,
  getTopicUiKey,
  countRoutingTextList,
  onUpdateTopicLocal,
  onToggleExpandedTopic,
  onRemoveTopic,
  onSaveTopic,
  onSetNewTopicPanelOpen,
  onSetTopicPresetMenuOpen,
  onSetNewTopicAdvancedOpen,
  onResetNewTopicDraft,
  onNormalizeTopicKeyInput,
  onSetNewTopicKey,
  onSetNewTopicName,
  onSetNewTopicDescription,
  onSetNewTopicPurpose,
  onSetNewTopicIncludeWhen,
  onSetNewTopicExcludeWhen,
  onSetNewTopicExamplesPositive,
  onSetNewTopicExamplesNegative,
  onSetNewTopicPriority,
  onBeginTopicCreate,
  onResolvePresetLabel,
  onAddTopic,
}: TopicConfigModalProps) {
  if (!open) return null;

  return (
    <DrawerShell
      open={open}
      onClose={onClose}
      title={labels.topicPanel}
      subtitle={labels.topicPanelDesc}
      size="extend"
      closeLabel={labels.close}
      bodyClassName="ops-config-drawer-body"
      footer={(
        !newTopicPanelOpen ? (
          <div className="drawer-shell-footer-content">
            <div className="drawer-shell-footer-main field-label">{labels.topicAddHint}</div>
            <div className="ops-topic-create-menu-wrap" ref={topicPresetMenuRef}>
              <button className="btn btn-primary" disabled={isSavingTopic || !hasSelectedBot} onClick={() => onSetTopicPresetMenuOpen((prev) => !prev)}>
                <Plus size={14} />
                <span style={{ marginLeft: 6 }}>{labels.topicAdd}</span>
              </button>
              {topicPresetMenuOpen ? (
                <div className="ops-topic-create-menu">
                  {effectiveTopicPresetTemplates.map((preset) => (
                    <button key={preset.id} className="ops-topic-create-menu-item" onClick={() => onBeginTopicCreate(preset.id)}>
                      {onResolvePresetLabel(preset)}
                    </button>
                  ))}
                  <button className="ops-topic-create-menu-item" onClick={() => onBeginTopicCreate('blank')}>{labels.topicPresetBlank}</button>
                </div>
              ) : null}
            </div>
          </div>
        ) : undefined
      )}
    >
      <div className="ops-config-modal">
        <div className="card" style={{ fontSize: 12, color: 'var(--muted)' }}>
          {labels.topicPanelDesc}
        </div>
        <div className="wizard-channel-list ops-config-list-scroll">
          {topics.length === 0 ? (
            <div className="ops-empty-inline">{labels.topicEmpty}</div>
          ) : (
            topics.map((topic, idx) => {
              const uiKey = getTopicUiKey(topic, idx);
              const expanded = expandedTopicByKey[uiKey] ?? idx === 0;
              const includeCount = countRoutingTextList(String(topic.routing_include_when || ''));
              const excludeCount = countRoutingTextList(String(topic.routing_exclude_when || ''));
              return (
                <div key={`${topic.id}-${topic.topic_key}`} className="card wizard-channel-card wizard-channel-compact">
                  <div className="ops-config-card-header">
                    <div className="ops-config-card-main">
                      <strong className="mono">{topic.topic_key}</strong>
                      <div className="field-label">{topic.name || topic.topic_key}</div>
                      {!expanded ? (
                        <div className="ops-config-collapsed-meta">
                          {`${labels.topicPriority}: ${topic.routing_priority || '50'} · ${isZh ? '命中' : 'include'} ${includeCount} · ${isZh ? '排除' : 'exclude'} ${excludeCount}`}
                        </div>
                      ) : null}
                    </div>
                    <div className="ops-config-card-actions">
                      <label className="field-label">
                        <input
                          type="checkbox"
                          checked={Boolean(topic.is_active)}
                          onChange={(e) => onUpdateTopicLocal(idx, { is_active: e.target.checked })}
                          style={{ marginRight: 6 }}
                        />
                        {labels.topicActive}
                      </label>
                      <LucentIconButton
                        className="btn btn-danger btn-sm wizard-icon-btn"
                        disabled={isSavingTopic}
                        onClick={() => void onRemoveTopic(topic)}
                        tooltip={labels.delete}
                        aria-label={labels.delete}
                      >
                        <Trash2 size={14} />
                      </LucentIconButton>
                      <LucentIconButton
                        className="ops-plain-icon-btn"
                        onClick={() => onToggleExpandedTopic(uiKey)}
                        tooltip={expanded ? (isZh ? '收起详情' : 'Collapse') : (isZh ? '展开详情' : 'Expand')}
                        aria-label={expanded ? (isZh ? '收起详情' : 'Collapse') : (isZh ? '展开详情' : 'Expand')}
                      >
                        {expanded ? <ChevronUp size={14} /> : <ChevronDown size={14} />}
                      </LucentIconButton>
                    </div>
                  </div>
                  {expanded ? (
                    <>
                      <div className="ops-topic-grid">
                        <div className="ops-config-field">
                          <label className="field-label">{labels.topicName}</label>
                          <input className="input" value={topic.name || ''} onChange={(e) => onUpdateTopicLocal(idx, { name: e.target.value })} placeholder={labels.topicName} />
                        </div>
                        <div className="ops-config-field">
                          <label className="field-label">{labels.topicPriority}</label>
                          <input className="input mono" type="number" min={0} max={100} step={1} value={topic.routing_priority || '50'} onChange={(e) => onUpdateTopicLocal(idx, { routing_priority: e.target.value })} />
                        </div>
                        <div className="ops-config-field ops-config-field-full">
                          <label className="field-label">{labels.topicDescription}</label>
                          <textarea className="input" rows={3} value={topic.description || ''} onChange={(e) => onUpdateTopicLocal(idx, { description: e.target.value })} placeholder={labels.topicDescription} />
                        </div>
                        <div className="ops-config-field ops-config-field-full">
                          <label className="field-label">{labels.topicPurpose}</label>
                          <textarea className="input" rows={3} value={topic.routing_purpose || ''} onChange={(e) => onUpdateTopicLocal(idx, { routing_purpose: e.target.value })} placeholder={labels.topicPurpose} />
                        </div>
                        <div className="ops-config-field">
                          <label className="field-label">{labels.topicIncludeWhen}</label>
                          <textarea className="input mono" rows={4} value={topic.routing_include_when || ''} onChange={(e) => onUpdateTopicLocal(idx, { routing_include_when: e.target.value })} placeholder={labels.topicListHint} />
                        </div>
                        <div className="ops-config-field">
                          <label className="field-label">{labels.topicExcludeWhen}</label>
                          <textarea className="input mono" rows={4} value={topic.routing_exclude_when || ''} onChange={(e) => onUpdateTopicLocal(idx, { routing_exclude_when: e.target.value })} placeholder={labels.topicListHint} />
                        </div>
                        <div className="ops-config-field">
                          <label className="field-label">{labels.topicExamplesPositive}</label>
                          <textarea className="input mono" rows={4} value={topic.routing_examples_positive || ''} onChange={(e) => onUpdateTopicLocal(idx, { routing_examples_positive: e.target.value })} placeholder={labels.topicListHint} />
                        </div>
                        <div className="ops-config-field">
                          <label className="field-label">{labels.topicExamplesNegative}</label>
                          <textarea className="input mono" rows={4} value={topic.routing_examples_negative || ''} onChange={(e) => onUpdateTopicLocal(idx, { routing_examples_negative: e.target.value })} placeholder={labels.topicListHint} />
                        </div>
                      </div>
                      <div className="row-between ops-config-footer">
                        <span className="field-label">{labels.topicAddHint}</span>
                        <button className="btn btn-primary btn-sm" disabled={isSavingTopic} onClick={() => void onSaveTopic(topic)}>
                          {isSavingTopic ? <RefreshCw size={14} className="animate-spin" /> : <Save size={14} />}
                          <span style={{ marginLeft: 6 }}>{labels.save}</span>
                        </button>
                      </div>
                    </>
                  ) : null}
                </div>
              );
            })
          )}
        </div>
        {newTopicPanelOpen ? (
          <div className="card wizard-channel-card wizard-channel-compact ops-config-new-card">
            <div className="ops-config-card-header">
              <div className="ops-config-card-main">
                <strong>{labels.topicAdd}</strong>
                <div className="ops-config-collapsed-meta">{newTopicSourceLabel}</div>
              </div>
              <div className="ops-config-card-actions">
                <LucentIconButton
                  className="ops-plain-icon-btn"
                  onClick={() => onSetNewTopicAdvancedOpen((prev) => !prev)}
                  tooltip={newTopicAdvancedOpen ? (isZh ? '收起高级路由' : 'Hide Advanced') : (isZh ? '展开高级路由' : 'Show Advanced')}
                  aria-label={newTopicAdvancedOpen ? (isZh ? '收起高级路由' : 'Hide Advanced') : (isZh ? '展开高级路由' : 'Show Advanced')}
                >
                  {newTopicAdvancedOpen ? <ChevronUp size={15} /> : <ChevronDown size={15} />}
                </LucentIconButton>
                <LucentIconButton
                  className="ops-plain-icon-btn"
                  onClick={() => {
                    onSetNewTopicPanelOpen(false);
                    onSetTopicPresetMenuOpen(false);
                    onResetNewTopicDraft();
                  }}
                  tooltip={labels.cancel}
                  aria-label={labels.cancel}
                >
                  <X size={15} />
                </LucentIconButton>
              </div>
            </div>
            <div className="ops-topic-grid">
              <div className="ops-config-field">
                <label className="field-label">{labels.topicKey}</label>
                <input className="input mono" value={newTopicKey} onChange={(e) => onSetNewTopicKey(onNormalizeTopicKeyInput(e.target.value))} placeholder={labels.topicKeyPlaceholder} autoComplete="off" />
              </div>
              <div className="ops-config-field">
                <label className="field-label">{labels.topicName}</label>
                <input className="input" value={newTopicName} onChange={(e) => onSetNewTopicName(e.target.value)} placeholder={labels.topicName} autoComplete="off" />
              </div>
              <div className="ops-config-field ops-config-field-full">
                <label className="field-label">{labels.topicDescription}</label>
                <textarea className="input" rows={3} value={newTopicDescription} onChange={(e) => onSetNewTopicDescription(e.target.value)} placeholder={labels.topicDescription} />
              </div>
              {newTopicAdvancedOpen ? (
                <>
                  <div className="ops-config-field ops-config-field-full">
                    <label className="field-label">{labels.topicPurpose}</label>
                    <textarea className="input" rows={3} value={newTopicPurpose} onChange={(e) => onSetNewTopicPurpose(e.target.value)} placeholder={labels.topicPurpose} />
                  </div>
                  <div className="ops-config-field">
                    <label className="field-label">{labels.topicIncludeWhen}</label>
                    <textarea className="input mono" rows={4} value={newTopicIncludeWhen} onChange={(e) => onSetNewTopicIncludeWhen(e.target.value)} placeholder={labels.topicListHint} />
                  </div>
                  <div className="ops-config-field">
                    <label className="field-label">{labels.topicExcludeWhen}</label>
                    <textarea className="input mono" rows={4} value={newTopicExcludeWhen} onChange={(e) => onSetNewTopicExcludeWhen(e.target.value)} placeholder={labels.topicListHint} />
                  </div>
                  <div className="ops-config-field">
                    <label className="field-label">{labels.topicExamplesPositive}</label>
                    <textarea className="input mono" rows={4} value={newTopicExamplesPositive} onChange={(e) => onSetNewTopicExamplesPositive(e.target.value)} placeholder={labels.topicListHint} />
                  </div>
                  <div className="ops-config-field">
                    <label className="field-label">{labels.topicExamplesNegative}</label>
                    <textarea className="input mono" rows={4} value={newTopicExamplesNegative} onChange={(e) => onSetNewTopicExamplesNegative(e.target.value)} placeholder={labels.topicListHint} />
                  </div>
                  <div className="ops-config-field">
                    <label className="field-label">{labels.topicPriority}</label>
                    <input className="input mono" type="number" min={0} max={100} step={1} value={newTopicPriority} onChange={(e) => onSetNewTopicPriority(e.target.value)} />
                  </div>
                </>
              ) : null}
            </div>
            <div className="row-between ops-config-footer">
              <span className="field-label">{labels.topicAddHint}</span>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
                <button
                  className="btn btn-secondary btn-sm"
                  disabled={isSavingTopic}
                  onClick={() => {
                    onSetNewTopicPanelOpen(false);
                    onSetTopicPresetMenuOpen(false);
                    onResetNewTopicDraft();
                  }}
                >
                  {labels.cancel}
                </button>
                <button className="btn btn-primary btn-sm" disabled={isSavingTopic || !hasSelectedBot} onClick={() => void onAddTopic()}>
                  <Save size={14} />
                  <span style={{ marginLeft: 6 }}>{labels.save}</span>
                </button>
              </div>
            </div>
          </div>
        ) : null}
      </div>
    </DrawerShell>
  );
}
