import { useEffect, useState, type FormEvent } from 'react';
import { Database, Pencil, Plus, RotateCcw, Save, ServerCog, Trash2 } from 'lucide-react';
import type { FileStorageChannel, FileStorageChannelUpsertRequest, FileStorageSettings, FileStorageSettingsUpdateRequest } from '@easyai-ai-gateway/contracts';
import { Badge, Button, Card, CardContent, CardHeader, CardTitle, ConfirmDialog, FormDialog, Input, Label, Select, Tabs, Textarea } from '../../components/ui';
import type { LoadState } from '../../types';

type SystemSettingsTab = 'fileStorage';

type FileStorageChannelForm = {
  apiKey: string;
  apiKeyPreview: string;
  channelKey: string;
  configJson: string;
  name: string;
  priority: string;
  provider: string;
  retryPolicyJson: string;
  scenes: string[];
  status: string;
  uploadUrl: string;
};

const defaultUploadUrl = 'http://127.0.0.1:3001/v1/files/upload';
const defaultRetryPolicy = {
  enabled: true,
  maxRetries: 3,
  backoffSeconds: [60, 120, 180],
  strategy: 'exponential',
};

const providerOptions = [
  { value: 'server_main_openapi', label: 'server-main OpenAPI' },
  { value: 'aliyun_oss', label: '阿里云 OSS' },
  { value: 'tencent_cos', label: '腾讯云 COS' },
];

const defaultScenes = ['upload', 'image_result'];
const sceneOptions = [
  { value: 'upload', label: '上传', description: 'OpenAPI / 管理端主动上传文件' },
  { value: 'image_result', label: '返图', description: '模型返回 base64 / buffer 图片或视频后的转存' },
];

const resultUploadPolicyOptions = [
  { value: 'default', label: '默认：仅非链接资源转存', description: 'URL 结果直接保存；base64 / buffer 等结果转存后保存 URL' },
  { value: 'upload_all', label: '全部转存', description: 'URL、base64、buffer 等返图结果都会转存到当前文件渠道' },
  { value: 'upload_none', label: '全部不转存', description: '链接结果直接保存；base64 / buffer 结果写入网关本地静态托管后保存 URL' },
];

export function SystemSettingsPanel(props: {
  channels: FileStorageChannel[];
  message: string;
  settings: FileStorageSettings | null;
  state: LoadState;
  onDeleteFileStorageChannel: (channelId: string) => Promise<void>;
  onSaveFileStorageChannel: (input: FileStorageChannelUpsertRequest, channelId?: string) => Promise<void>;
  onSaveFileStorageSettings: (input: FileStorageSettingsUpdateRequest) => Promise<void>;
}) {
  const [activeTab, setActiveTab] = useState<SystemSettingsTab>('fileStorage');
  const [dialogOpen, setDialogOpen] = useState(false);
  const [editingChannel, setEditingChannel] = useState<FileStorageChannel | null>(null);
  const [pendingDeleteChannel, setPendingDeleteChannel] = useState<FileStorageChannel | null>(null);
  const [form, setForm] = useState<FileStorageChannelForm>(() => defaultChannelForm());
  const [settingsPolicy, setSettingsPolicy] = useState(() => normalizeResultUploadPolicy(props.settings?.resultUploadPolicy));
  const [localError, setLocalError] = useState('');

  useEffect(() => {
    setSettingsPolicy(normalizeResultUploadPolicy(props.settings?.resultUploadPolicy));
  }, [props.settings?.resultUploadPolicy]);

  function openCreateDialog() {
    setEditingChannel(null);
    setForm(defaultChannelForm(`server-main-${Date.now().toString(36)}`));
    setLocalError('');
    setDialogOpen(true);
  }

  function editChannel(channel: FileStorageChannel) {
    setEditingChannel(channel);
    setForm(channelToForm(channel));
    setLocalError('');
    setDialogOpen(true);
  }

  function closeDialog() {
    setEditingChannel(null);
    setForm(defaultChannelForm());
    setLocalError('');
    setDialogOpen(false);
  }

  async function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setLocalError('');
    if (form.scenes.length === 0) {
      setLocalError('请至少选择一个适用场景。');
      return;
    }
    try {
      await props.onSaveFileStorageChannel(formToPayload(form), editingChannel?.id);
      closeDialog();
    } catch (err) {
      setLocalError(err instanceof Error ? err.message : '文件存储渠道保存失败');
    }
  }

  async function deleteChannel(channel: FileStorageChannel) {
    try {
      await props.onDeleteFileStorageChannel(channel.id);
      setPendingDeleteChannel(null);
      if (editingChannel?.id === channel.id) closeDialog();
    } catch (err) {
      setLocalError(err instanceof Error ? err.message : '文件存储渠道删除失败');
    }
  }

  async function saveSettings() {
    setLocalError('');
    try {
      await props.onSaveFileStorageSettings({ resultUploadPolicy: normalizeResultUploadPolicy(settingsPolicy) });
    } catch (err) {
      setLocalError(err instanceof Error ? err.message : '文件存储全局策略保存失败');
    }
  }

  return (
    <div className="pageStack">
      <Card>
        <CardHeader>
          <div>
            <CardTitle>系统设置</CardTitle>
            <p className="mutedText">集中维护网关级配置；文件存储渠道按优先级轮转，单渠道使用 60/120/180 秒退避重试。</p>
          </div>
          <Badge variant="secondary">{props.channels.length} 个文件渠道</Badge>
        </CardHeader>
        <CardContent>
          {(props.message || localError) && <p className="formMessage">{localError || props.message}</p>}
          <Tabs
            value={activeTab}
            tabs={[{ value: 'fileStorage', label: '文件存储', icon: <Database size={15} /> }]}
            onValueChange={setActiveTab}
          />
        </CardContent>
      </Card>

      {activeTab === 'fileStorage' && (
        <section className="fileStoragePanel">
          <div className="fileStorageSettingsCard">
            <div>
              <strong>全局返图转存策略</strong>
              <span>对所有返图场景统一生效；渠道只负责上传目标、凭证、重试和轮转。</span>
            </div>
            <Label>
              策略
              <Select value={settingsPolicy} onChange={(event) => setSettingsPolicy(event.target.value)}>
                {resultUploadPolicyOptions.map((item) => <option value={item.value} key={item.value}>{item.label}</option>)}
              </Select>
              <small>{resultUploadPolicyDescription(settingsPolicy)}</small>
            </Label>
            <Button type="button" onClick={saveSettings} disabled={props.state === 'loading'}>
              <Save size={15} />
              保存策略
            </Button>
          </div>

          <div className="fileStorageToolbar">
            <div>
              <strong>文件存储渠道</strong>
              <span>server-main OpenAPI 渠道只需要上传路由和 API Key。</span>
            </div>
            <Button type="button" onClick={openCreateDialog}>
              <Plus size={15} />
              新增渠道
            </Button>
          </div>

          <div className="fileStorageGrid">
            {props.channels.map((channel) => (
              <article className="fileStorageCard" key={channel.id}>
                <header>
                  <div className="iconBox"><ServerCog size={18} /></div>
                  <div>
                    <strong>{channel.name}</strong>
                    <span>{channel.channelKey}</span>
                  </div>
                  <Badge variant={channel.status === 'enabled' ? 'success' : 'secondary'}>{channel.status}</Badge>
                </header>
                <div className="fileStorageMeta">
                  <span>渠道: {providerLabel(channel.provider)}</span>
                  <span>场景: {sceneSummary(channel.scenes)}</span>
                  <span>优先级: {channel.priority}</span>
                  <span>重试: {retryPolicySummary(channel.retryPolicy)}</span>
                  {channel.uploadUrl && <span>上传路由: {channel.uploadUrl}</span>}
                  {apiKeyPreview(channel) && <span>API Key: {apiKeyPreview(channel)}</span>}
                  {channel.lastError && <span>最近错误: {channel.lastError}</span>}
                </div>
                <footer>
                  <Button type="button" variant="outline" size="sm" onClick={() => editChannel(channel)}>
                    <Pencil size={14} />
                    修改
                  </Button>
                  <Button type="button" variant="destructive" size="sm" onClick={() => setPendingDeleteChannel(channel)}>
                    <Trash2 size={14} />
                    删除
                  </Button>
                </footer>
              </article>
            ))}
            {!props.channels.length && (
              <Card>
                <CardContent className="emptyState">
                  <strong>暂无文件存储渠道</strong>
                </CardContent>
              </Card>
            )}
          </div>
        </section>
      )}

      <FormDialog
        ariaLabel={editingChannel ? '编辑文件存储渠道' : '新增文件存储渠道'}
        bodyClassName="fileStorageDialogBody"
        eyebrow={editingChannel ? 'Edit Storage Channel' : 'New Storage Channel'}
        footer={(
          <>
            <Button type="submit" disabled={props.state === 'loading'}>
              {editingChannel ? <Save size={15} /> : <Plus size={15} />}
              {editingChannel ? '保存渠道' : '新增渠道'}
            </Button>
            <Button type="button" variant="outline" onClick={closeDialog}>
              <RotateCcw size={15} />
              取消
            </Button>
          </>
        )}
        open={dialogOpen}
        title={editingChannel ? '编辑文件存储渠道' : '新增文件存储渠道'}
        onClose={closeDialog}
        onSubmit={submit}
      >
        <Label>
          渠道标识
          <Input value={form.channelKey} onChange={(event) => setForm({ ...form, channelKey: event.target.value })} placeholder="server-main-openapi" />
        </Label>
        <Label>
          渠道名称
          <Input value={form.name} onChange={(event) => setForm({ ...form, name: event.target.value })} placeholder="server-main OpenAPI" />
        </Label>
        <Label>
          渠道类型
          <Select value={form.provider} onChange={(event) => setForm({ ...form, provider: event.target.value })}>
            {providerOptions.map((item) => <option value={item.value} key={item.value}>{item.label}</option>)}
          </Select>
        </Label>
        <Label>
          状态
          <Select value={form.status} onChange={(event) => setForm({ ...form, status: event.target.value })}>
            <option value="enabled">enabled</option>
            <option value="disabled">disabled</option>
          </Select>
        </Label>
        <Label className="spanTwo">
          适用场景
          <div className="fileStorageSceneGrid">
            {sceneOptions.map((scene) => (
              <FileStorageSceneToggle
                checked={form.scenes.includes(scene.value)}
                description={scene.description}
                key={scene.value}
                label={scene.label}
                onChange={(checked) => setForm({ ...form, scenes: nextScenes(form.scenes, scene.value, checked) })}
              />
            ))}
          </div>
        </Label>
        <Label className="spanTwo">
          上传路由
          <Input value={form.uploadUrl} onChange={(event) => setForm({ ...form, uploadUrl: event.target.value })} placeholder={defaultUploadUrl} />
        </Label>
        <Label className="platformCredentialField">
          API Key
          <Input value={form.apiKey} onChange={(event) => setForm({ ...form, apiKey: event.target.value })} placeholder={credentialInputPlaceholder(form.apiKeyPreview)} />
          <small>保持脱敏值不变表示不修改；填写新值表示覆盖；清空后保存表示清除。</small>
        </Label>
        <Label>
          优先级
          <Input type="number" min={1} value={form.priority} onChange={(event) => setForm({ ...form, priority: event.target.value })} />
        </Label>
        <Label className="spanTwo">
          重试策略 JSON
          <Textarea value={form.retryPolicyJson} onChange={(event) => setForm({ ...form, retryPolicyJson: event.target.value })} />
        </Label>
        <Label className="spanTwo">
          扩展配置 JSON
          <Textarea value={form.configJson} onChange={(event) => setForm({ ...form, configJson: event.target.value })} />
        </Label>
      </FormDialog>

      <ConfirmDialog
        confirmLabel="删除渠道"
        description="删除后该文件存储渠道不会再参与上传轮转。"
        loading={props.state === 'loading'}
        open={Boolean(pendingDeleteChannel)}
        title={`确认删除文件存储渠道 ${pendingDeleteChannel?.name ?? ''}？`}
        onCancel={() => setPendingDeleteChannel(null)}
        onConfirm={() => pendingDeleteChannel ? deleteChannel(pendingDeleteChannel) : undefined}
      />
    </div>
  );
}

function defaultChannelForm(channelKey = ''): FileStorageChannelForm {
  return {
    apiKey: '',
    apiKeyPreview: '',
    channelKey,
    configJson: '{}',
    name: 'server-main OpenAPI',
    priority: '100',
    provider: 'server_main_openapi',
    retryPolicyJson: stringifyJson(defaultRetryPolicy),
    scenes: defaultScenes,
    status: 'disabled',
    uploadUrl: defaultUploadUrl,
  };
}

function channelToForm(channel: FileStorageChannel): FileStorageChannelForm {
  const preview = apiKeyPreview(channel);
  return {
    apiKey: preview,
    apiKeyPreview: preview,
    channelKey: channel.channelKey,
    configJson: stringifyJson(channel.config ?? {}),
    name: channel.name,
    priority: String(channel.priority || 100),
    provider: channel.provider || 'server_main_openapi',
    retryPolicyJson: stringifyJson(channel.retryPolicy ?? defaultRetryPolicy),
    scenes: normalizeScenes(channel.scenes),
    status: channel.status || 'disabled',
    uploadUrl: channel.uploadUrl || defaultUploadUrl,
  };
}

function formToPayload(form: FileStorageChannelForm): FileStorageChannelUpsertRequest {
  return {
    apiKey: apiKeyPayloadValue(form),
    channelKey: form.channelKey.trim(),
    config: parseJsonObject(form.configJson, '扩展配置 JSON'),
    name: form.name.trim(),
    priority: Number(form.priority) || 100,
    provider: form.provider,
    retryPolicy: parseJsonObject(form.retryPolicyJson, '重试策略 JSON'),
    scenes: normalizeScenes(form.scenes),
    status: form.status,
    uploadUrl: form.uploadUrl.trim(),
  };
}

function parseJsonObject(value: string, label: string) {
  try {
    const parsed = JSON.parse(value || '{}') as unknown;
    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
      throw new Error(`${label} 必须是对象`);
    }
    return parsed as Record<string, unknown>;
  } catch (err) {
    if (err instanceof Error && err.message.includes(label)) throw err;
    throw new Error(`${label} 格式不正确`);
  }
}

function stringifyJson(value: unknown) {
  return JSON.stringify(value ?? {}, null, 2);
}

function providerLabel(provider: string) {
  return providerOptions.find((item) => item.value === provider)?.label ?? provider;
}

function sceneSummary(scenes: string[] | undefined) {
  return normalizeScenes(scenes).map((scene) => sceneOptions.find((item) => item.value === scene)?.label ?? scene).join(' / ');
}

function normalizeResultUploadPolicy(value: string | undefined) {
  const normalized = (value || 'default').trim();
  return resultUploadPolicyOptions.some((item) => item.value === normalized) ? normalized : 'default';
}

function resultUploadPolicyDescription(value: string | undefined) {
  const normalized = normalizeResultUploadPolicy(value);
  return resultUploadPolicyOptions.find((item) => item.value === normalized)?.description ?? '';
}

function normalizeScenes(scenes: string[] | undefined) {
  const next = Array.from(new Set((scenes ?? []).map((scene) => scene.trim()).filter(Boolean)));
  return next.length ? next : [...defaultScenes];
}

function nextScenes(current: string[], scene: string, checked: boolean) {
  if (checked) return normalizeScenes([...current, scene]);
  return current.filter((item) => item !== scene);
}

function retryPolicySummary(policy?: Record<string, unknown>) {
  const maxRetries = numberFromUnknown(policy?.maxRetries) || 3;
  const backoff = Array.isArray(policy?.backoffSeconds) ? policy?.backoffSeconds.join('/') : '60/120/180';
  return `${maxRetries} 次 · ${backoff}s`;
}

function apiKeyPreview(channel: FileStorageChannel) {
  const value = channel.credentialsPreview?.apiKey;
  return typeof value === 'string' ? value : '';
}

function apiKeyPayloadValue(form: FileStorageChannelForm) {
  const value = form.apiKey.trim();
  if (form.apiKeyPreview && value === form.apiKeyPreview) return undefined;
  return value || (form.apiKeyPreview ? '' : undefined);
}

function credentialInputPlaceholder(preview: string) {
  return preview ? '填写新凭证以覆盖当前值' : 'sk-...';
}

function FileStorageSceneToggle(props: { checked: boolean; description: string; label: string; onChange: (checked: boolean) => void }) {
  return (
    <label className="platformToggle">
      <input type="checkbox" checked={props.checked} onChange={(event) => props.onChange(event.target.checked)} />
      <span>
        <strong>{props.label}</strong>
        <small>{props.description}</small>
      </span>
    </label>
  );
}

function numberFromUnknown(value: unknown) {
  if (typeof value === 'number' && Number.isFinite(value)) return value;
  if (typeof value === 'string' && value.trim()) {
    const parsed = Number(value);
    if (Number.isFinite(parsed)) return parsed;
  }
  return 0;
}
