// ============================================================
// ModelInputForm — 动态模型输入表单
// 根据选中模型的 param_schema + ui_config 动态渲染表单控件
// ============================================================

import { useState, useEffect, useMemo, useCallback } from 'react';
import {
   Form,
   Input,
   InputNumber,
   Select,
   Slider,
   Button,
   Typography,
   Empty,
   Upload,
   Switch,
   theme as antTheme,
   message,
} from 'antd';
import {
   SendOutlined,
   UploadOutlined,
   InboxOutlined,
} from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload';

import { useHomeContext } from '@/contexts/home-context';
import { useAppContext } from '@/contexts/app-context';
import { useSubmitTask } from '@/hooks/use-api';
import { emit, EVENTS } from '@/utils/event-bus';
import type { ModelsListResponseBody, TaskInfoItemResponseBody } from '@/services/modules';

const { Text, Title } = Typography;
const { TextArea } = Input;
const { Dragger } = Upload;

// ---------- 参数类型映射 ----------

/** 从 ui_config 中解析的参数描述 */
interface ParamDescriptor {
   /** React key（item.id，保证唯一） */
   key: string;
   /** API 字段名（item.map_to） */
   name: string;
   label: string;
   /** 控件类型 */
   controlType: 'text' | 'number' | 'textarea' | 'select' | 'slider' | 'switch' | 'image-upload';
   defaultValue?: unknown;
   required?: boolean;
   placeholder?: string;
   /** 数值型：最小值 */
   min?: number;
   /** 数值型：最大值 */
   max?: number;
   /** 数值型：步长 */
   step?: number;
   /** select 型：选项列表 */
   options?: Array<{ label: string; value: string | number }>;
}

/** 从 ui_config 对象中解析控件类型 */
function inferControlType(config: Record<string, unknown>): ParamDescriptor['controlType'] {
   const type = config.type as string | undefined;
   if (!type) return 'text';

   switch (type) {
      case 'number':
      case 'integer':
      case 'float':
         return 'number';
      case 'textarea':
      case 'text_area':
      case 'prompt':
         return 'textarea';
      case 'select':
      case 'dropdown':
      case 'enum':
         return 'select';
      case 'slider':
      case 'range':
         return 'slider';
      case 'switch':
      case 'boolean':
      case 'bool':
         return 'switch';
      case 'image':
      case 'image-upload':
      case 'file':
         return 'image-upload';
      default:
         return 'text';
   }
}

/**
 * 从 param_schema 构建参数描述符列表
 *
 * 后端 param_schema 格式为 ParamSchemaItem[]（对象数组），
 * 每项的 ui 字段内嵌了控件类型、标签、校验规则等 UI 配置。
 */
function buildParamDescriptors(
   paramSchema: ModelsListResponseBody['param_schema'],
): ParamDescriptor[] {
   return paramSchema.map((item) => {
      const config = (item.ui || {}) as Record<string, unknown>;
      const controlType = inferControlType(config);
      return {
         key: item.id,
         name: item.map_to,
         label: (config.label as string) || item.map_to,
         controlType,
         defaultValue: config.default ?? config.defaultValue,
         required: (config.required as boolean) || false,
         placeholder: (config.placeholder as string) || `请输入${config.label || item.map_to}`,
         min: config.min as number | undefined,
         max: config.max as number | undefined,
         step: config.step as number | undefined,
         options: (config.options as ParamDescriptor['options']) || undefined,
      };
   });
}

// ---------- 组件 ----------

export function ModelInputForm() {
   const { token } = antTheme.useToken();
   const { isLoggedIn } = useAppContext();
   const { selectedModel } = useHomeContext();
   const [form] = Form.useForm();
   const [referenceFiles, setReferenceFiles] = useState<UploadFile[]>([]);

   // 提交突变 Hook（自动处理 loading / error / 日志）
   const { execute: submitTask, loading: submitting, errorMessage } = useSubmitTask({
      onSuccess: useCallback(
         (_data: TaskInfoItemResponseBody) => {
            message.success('任务已提交');
            // 通过事件总线通知 TaskHistory 刷新（替代 Context 中的 refreshTaskSignal）
            emit(EVENTS.TASK_SUBMITTED);
         },
         [],
      ),
   });

   // 选中模型时重置表单（仅当有选中模型时操作，避免 form 未连接警告）
   useEffect(() => {
      if (selectedModel) {
         form.resetFields();
      }
      setReferenceFiles([]);
   }, [selectedModel?.id]); // eslint-disable-line react-hooks/exhaustive-deps

   // 参数描述符
   const paramDescriptors = useMemo(() => {
      if (!selectedModel) return [];
      return buildParamDescriptors(selectedModel.param_schema || []);
   }, [selectedModel]);

   // 提交
   const handleSubmit = async () => {
      if (!isLoggedIn) {
         message.warning('请先登录后再提交任务');
         return;
      }
      if (!selectedModel) return;

      try {
         const values = await form.validateFields();

         // 分离固定字段和模型动态参数
         const { prompt, negative_prompt, num_outputs, ...dynamicParams } = values;

         // 构建提交参数（全部转为字符串值）
         const params: Record<string, string> = {
            prompt: String(prompt ?? ''),
            negative_prompt: String(negative_prompt ?? ''),
            num_outputs: String(num_outputs ?? 1),
         };

         // 动态参数统一转字符串
         for (const [key, value] of Object.entries(dynamicParams)) {
            if (value !== undefined && value !== null) {
               params[key] = String(value);
            }
         }

         // 参考图
         if (referenceFiles.length > 0) {
            const refUrls = referenceFiles
               .filter((f) => f.status === 'done')
               .map((f) => f.response?.url || f.url || f.name)
               .filter(Boolean) as string[];
            if (refUrls.length > 0) {
               params.reference_images = JSON.stringify(refUrls);
            }
         }

         // 使用 mutation Hook 提交（自动处理 loading / error / 日志）
         await submitTask({ model_id: selectedModel.id, params });
      } catch (err) {
         if (err && typeof err === 'object' && 'errorFields' in err) {
            // 表单验证错误，antd 会自动提示
            return;
         }
         // 错误消息由 Hook 自动通过 errorMessage 提供
         message.error(errorMessage || '任务提交失败，请重试');
      }
   };

   // 渲染单个参数控件
   const renderParamControl = (desc: ParamDescriptor) => {
      const commonProps = {
         placeholder: desc.placeholder,
         style: { width: '100%' },
      };

      switch (desc.controlType) {
         case 'number':
            return (
               <InputNumber
                  {...commonProps}
                  min={desc.min}
                  max={desc.max}
                  step={desc.step}
                  style={{ width: '100%' }}
               />
            );

         case 'textarea':
            return <TextArea rows={3} {...commonProps} />;

         case 'select':
            return (
               <Select
                  {...commonProps}
                  options={desc.options}
                  allowClear
               />
            );

         case 'slider':
            return (
               <Slider
                  min={desc.min ?? 1}
                  max={desc.max ?? 100}
                  step={desc.step ?? 1}
                  marks={
                     desc.min !== undefined && desc.max !== undefined
                        ? { [desc.min]: `${desc.min}`, [desc.max]: `${desc.max}` }
                        : undefined
                  }
                  tooltip={{ formatter: (v) => v }}
               />
            );

         case 'switch':
            return <Switch />;

         case 'image-upload':
            return (
               <Upload
                  listType="picture-card"
                  maxCount={1}
                  accept="image/png,image/jpg,image/jpeg,image/webp"
                  beforeUpload={(file) => {
                     const isImage = file.type.startsWith('image/');
                     const isLt10M = file.size / 1024 / 1024 < 10;
                     if (!isImage) {
                        message.error('只能上传图片文件');
                        return Upload.LIST_IGNORE;
                     }
                     if (!isLt10M) {
                        message.error('图片大小不能超过 10MB');
                        return Upload.LIST_IGNORE;
                     }
                     return false; // 手动上传
                  }}
               >
                  <div>
                     <UploadOutlined />
                     <div style={{ marginTop: 4, fontSize: 12 }}>上传</div>
                  </div>
               </Upload>
            );

         default:
            return <Input {...commonProps} />;
      }
   };

   // ---- 未选择模型 ----
   if (!selectedModel) {
      return (
         <div
            style={{
               display: 'flex',
               alignItems: 'center',
               justifyContent: 'center',
               height: '100%',
            }}
         >
            <Empty description="请在左侧选择一个模型" image={Empty.PRESENTED_IMAGE_SIMPLE} />
         </div>
      );
   }

   // ---- 表单 ----
   return (
      <div
         style={{
            height: '100%',
            display: 'flex',
            flexDirection: 'column',
            overflow: 'hidden',
         }}
      >
         {/* 模型标题 */}
         <div
            style={{
               padding: '16px 20px',
               borderBottom: `1px solid ${token.colorBorderSecondary}`,
               flexShrink: 0,
            }}
         >
            <Title level={4} style={{ margin: 0, fontSize: 18 }}>
               {selectedModel.name}
            </Title>
            <Text type="secondary" style={{ fontSize: 12 }}>
               {selectedModel.provider_name} · {selectedModel.category_name}
            </Text>
         </div>

         {/* 可滚动表单区 */}
         <div style={{ flex: 1, overflow: 'auto', padding: '16px 20px' }}>
            <Form
               form={form}
               layout="vertical"
               size="small"
               initialValues={{ num_outputs: 1 }}
            >
               {/* ======== 固定字段 ======== */}

               {/* 提示词 */}
               <Form.Item
                  name="prompt"
                  label={<Text strong>提示词</Text>}
                  rules={[{ required: true, message: '请输入提示词' }]}
               >
                  <TextArea
                     rows={4}
                     placeholder="描述你想要的画面、视频或音频内容..."
                     showCount
                     maxLength={2000}
                  />
               </Form.Item>

               {/* 负面提示词 */}
               <Form.Item
                  name="negative_prompt"
                  label={<Text type="secondary">负面提示词</Text>}
               >
                  <TextArea
                     rows={2}
                     placeholder="描述你不希望在结果中出现的内容（可选）"
                     maxLength={1000}
                  />
               </Form.Item>

               {/* 参考图 */}
               <Form.Item label={<Text strong>参考图</Text>}>
                  <Dragger
                     multiple
                     listType="picture"
                     fileList={referenceFiles}
                     onChange={({ fileList }) => setReferenceFiles(fileList)}
                     accept="image/png,image/jpg,image/jpeg,image/webp"
                     beforeUpload={(file) => {
                        const isImage = file.type.startsWith('image/');
                        const isLt10M = file.size / 1024 / 1024 < 10;
                        if (!isImage) {
                           message.error('只能上传图片文件');
                           return Upload.LIST_IGNORE;
                        }
                        if (!isLt10M) {
                           message.error('图片大小不能超过 10MB');
                           return Upload.LIST_IGNORE;
                        }
                        return false;
                     }}
                     maxCount={5}
                     style={{ marginBottom: 8 }}
                  >
                     <p className="ant-upload-drag-icon">
                        <InboxOutlined />
                     </p>
                     <p className="ant-upload-text">点击或拖拽图片到此区域上传</p>
                     <p className="ant-upload-hint">
                        支持 PNG / JPG / WebP，单张不超过 10MB
                     </p>
                  </Dragger>
               </Form.Item>

               {/* 生成数量 */}
               <Form.Item
                  name="num_outputs"
                  label={<Text strong>生成数量</Text>}
               >
                  <InputNumber min={1} max={10} style={{ width: '100%' }} />
               </Form.Item>

               {/* ======== 模型动态参数 ======== */}

               {paramDescriptors.length > 0 && (
                  <div
                     style={{
                        marginTop: 16,
                        paddingTop: 16,
                        borderTop: `1px solid ${token.colorBorderSecondary}`,
                     }}
                  >
                     <Text strong style={{ display: 'block', marginBottom: 12 }}>
                        模型参数
                     </Text>
                     {paramDescriptors.map((desc) => (
                        <Form.Item
                           key={desc.key}
                           name={desc.name}
                           label={desc.label}
                           rules={desc.required ? [{ required: true, message: `请输入${desc.label}` }] : undefined}
                           initialValue={desc.defaultValue}
                           valuePropName={desc.controlType === 'switch' ? 'checked' : 'value'}
                        >
                           {renderParamControl(desc)}
                        </Form.Item>
                     ))}
                  </div>
               )}
            </Form>
         </div>

         {/* 提交按钮 */}
         <div
            style={{
               padding: '12px 20px',
               borderTop: `1px solid ${token.colorBorderSecondary}`,
               flexShrink: 0,
            }}
         >
            <Button
               type="primary"
               icon={<SendOutlined />}
               onClick={handleSubmit}
               loading={submitting}
               disabled={!isLoggedIn || !selectedModel}
               block
               size="large"
               style={{
                  background: token.colorPrimary,
                  height: 44,
                  fontSize: 16,
               }}
            >
               开始生成
            </Button>
         </div>
      </div>
   );
}
