// ============================================================
// SeedanceContent — seedance2Content → 内容编排控件
//
// 对应 Seedance 2.0 视频生成模型的 content 参数（json_array）。
// 内部值结构（JSON 字符串 ⟷ 表单字段值）：
//   { text: string; imageUrls: string[]; videoUrls: string[]; audioUrls: string[] }
//
// 从 param_schema.spec 读取 image_files / video_files / audio_files
// 决定各媒体类型的上传数量上限和是否显示对应上传区域。
// ============================================================

import { useCallback, useMemo } from 'react';
import { Upload, Input, Typography, message, theme as antTheme } from 'antd';
import {
  PictureOutlined,
  VideoCameraOutlined,
  AudioOutlined,
  InboxOutlined,
} from '@ant-design/icons';
import type { UploadFile, RcFile } from 'antd/es/upload';
import type { WidgetProps } from './types';
import { useFileUpload } from '@/shared/hooks/use-api';
import { ContextMenu } from '@/shared/components/ContextMenu';
import { getMediaRefImageMenu, getMediaRefBlankMenu } from '../../../controllers/menus';
import type { ContextMenuItems } from '@/shared/components/ContextMenu';

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

// ---------- 内部值类型 ----------

interface ContentValue {
  text: string;
  imageUrls: string[];
  videoUrls: string[];
  audioUrls: string[];
}

// ---------- 辅助函数 ----------

function parseValue(raw: unknown): ContentValue {
  if (typeof raw === 'string' && raw.startsWith('{')) {
    try {
      const obj = JSON.parse(raw) as Partial<ContentValue>;
      return {
        text: obj.text || '',
        imageUrls: Array.isArray(obj.imageUrls) ? obj.imageUrls : [],
        videoUrls: Array.isArray(obj.videoUrls) ? obj.videoUrls : [],
        audioUrls: Array.isArray(obj.audioUrls) ? obj.audioUrls : [],
      };
    } catch { /* ignore */ }
  }
  return { text: typeof raw === 'string' ? raw : '', imageUrls: [], videoUrls: [], audioUrls: [] };
}

function serializeValue(cv: ContentValue): string {
  return JSON.stringify(cv);
}

/** URL 数组 → UploadFile 数组（全部标记为 done） */
function urlsToFileList(urls: string[], type: string): UploadFile[] {
  return urls.map((url, i) => ({
    uid: `${type}-${i}-${url.slice(-20)}`,
    name: url.split('/').pop() || `${type}_${i + 1}`,
    status: 'done' as const,
    url,
  }));
}

/** 从 UploadFile 数组中提取已上传成功的 URL */
function extractUrls(fileList: UploadFile[]): string[] {
  return fileList
    .filter(f => f.status === 'done')
    .map(f => (f.response as { url?: string })?.url || f.url || '')
    .filter(Boolean);
}

// ---------- 上传区域子组件 ----------

interface UploadSectionProps {
  type: 'image' | 'video' | 'audio';
  urls: string[];
  maxCount: number;
  maxSizeMb: number;
  disabled: boolean;
  icon: React.ReactNode;
  label: string;
  customRequest: ReturnType<typeof useFileUpload>['customRequest'];
  onChange: (urls: string[]) => void;
  /** 可选：上传预览图区域的右键菜单项 */
  previewContextMenu?: ContextMenuItems;
}

function UploadSection({
  type, urls, maxCount, maxSizeMb, disabled, icon, label, customRequest, onChange, previewContextMenu,
}: UploadSectionProps) {
  const fileList = useMemo(() => urlsToFileList(urls, type), [urls, type]);

  const beforeUpload = useCallback((file: RcFile) => {
    const mimePrefix = type === 'image' ? 'image/' : type === 'video' ? 'video/' : 'audio/';
    if (!file.type.startsWith(mimePrefix)) {
      message.error(`只能上传${label}文件`);
      return Upload.LIST_IGNORE;
    }
    if (file.size / 1024 / 1024 >= maxSizeMb) {
      message.error(`${label}大小不能超过 ${maxSizeMb}MB`);
      return Upload.LIST_IGNORE;
    }
    return true;
  }, [type, label, maxSizeMb]);

  const handleChange = useCallback(
    (info: { fileList: UploadFile[] }) => {
      onChange(extractUrls(info.fileList));
    },
    [onChange],
  );

  if (maxCount <= 0) return null;

  const draggerNode = (
    <Dragger
        multiple={maxCount > 1}
        listType="picture"
        accept={type === 'image' ? 'image/*' : type === 'video' ? 'video/*' : 'audio/*'}
        fileList={fileList}
        customRequest={customRequest}
        onChange={handleChange}
        disabled={disabled}
        beforeUpload={beforeUpload}
        maxCount={maxCount}
      >
        <p className="ant-upload-drag-icon">
          <InboxOutlined />
        </p>
        <p className="ant-upload-text">点击或拖拽{label}到此区域上传</p>
        <p className="ant-upload-hint">单文件不超过 {maxSizeMb}MB</p>
      </Dragger>
  );

  return (
    <div style={{ marginTop: 8 }}>
      <Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
        {icon} {label}（最多 {maxCount} 个）
      </Text>
      {previewContextMenu ? (
        <ContextMenu items={previewContextMenu}>{draggerNode}</ContextMenu>
      ) : (
        draggerNode
      )}
    </div>
  );
}

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

export function SeedanceContent({ value, onChange, disabled, config }: WidgetProps) {
  const { token } = antTheme.useToken();
  const { customRequest } = useFileUpload();

  const cv = useMemo(() => parseValue(value), [value]);

  const imageFiles = (config.imageFiles as number) || 0;
  const videoFiles = (config.videoFiles as number) || 0;
  const audioFiles = (config.audioFiles as number) || 0;
  const maxSizeMb = (config.maxFileSizeMb as number) || 50;

  const emit = useCallback(
    (patch: Partial<ContentValue>) => {
      const next = { ...cv, ...patch };
      onChange?.(serializeValue(next));
    },
    [cv, onChange],
  );

  const handleTextChange = useCallback(
    (e: React.ChangeEvent<HTMLTextAreaElement>) => {
      emit({ text: e.target.value });
    },
    [emit],
  );

  // ── 右键菜单 ──

  const totalUploadedUrls = [...cv.imageUrls, ...cv.videoUrls, ...cv.audioUrls];
  const hasSelection = totalUploadedUrls.length > 0;

  const handleOpenFileList = useCallback(() => {
      message.info('打开文件列表功能待实现');
  }, []);

  const handleCopyToClipboard = useCallback(async () => {
      if (totalUploadedUrls.length > 0) {
          try {
              await navigator.clipboard.writeText(totalUploadedUrls.join('\n'));
              message.success('已复制文件链接');
          } catch {
              message.error('复制失败');
          }
      }
  }, [totalUploadedUrls]);

  const handleDeleteSelected = useCallback(() => {
      emit({ imageUrls: [], videoUrls: [], audioUrls: [] });
      message.success('已清空已选素材');
  }, [emit]);

  const imageMenuItems = getMediaRefImageMenu({
      hasSelection,
      onOpenFileList: handleOpenFileList,
      onCopyToClipboard: handleCopyToClipboard,
      onDeleteSelected: handleDeleteSelected,
  });

  const blankMenuItems = getMediaRefBlankMenu({
      hasSelection,
      onOpenFileList: handleOpenFileList,
      onCopyToClipboard: handleCopyToClipboard,
      onDeleteSelected: handleDeleteSelected,
  });

  return (
    <ContextMenu items={blankMenuItems}>
    <div
      style={{
        border: `1px dashed ${token.colorBorder}`,
        borderRadius: 6,
        padding: 12,
        background: token.colorFillQuaternary,
      }}
    >
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
        {(imageFiles > 0) && <PictureOutlined style={{ color: token.colorPrimary, fontSize: 14 }} />}
        {(videoFiles > 0) && <VideoCameraOutlined style={{ color: token.colorPrimary, fontSize: 14 }} />}
        {(audioFiles > 0) && <AudioOutlined style={{ color: token.colorPrimary, fontSize: 14 }} />}
        <Text type="secondary" style={{ fontSize: 12 }}>
          内容编排 — 描述动作 + 参考素材
        </Text>
      </div>

      <TextArea
        rows={4}
        value={cv.text}
        onChange={handleTextChange}
        disabled={disabled}
        placeholder={
          (config.placeholder as string) ||
          '输入视频内容的文字描述'
        }
        maxLength={(config.maxLength as number) || 5000}
        showCount
      />

      {/* 参考图片上传 */}
      {imageFiles > 0 && (
        <UploadSection
          type="image"
          urls={cv.imageUrls}
          maxCount={imageFiles}
          maxSizeMb={maxSizeMb}
          disabled={disabled ?? false}
          icon={<PictureOutlined />}
          label="参考图片"
          customRequest={customRequest}
          onChange={(urls) => emit({ imageUrls: urls })}
          previewContextMenu={imageMenuItems}
        />
      )}

      {/* 参考视频上传 */}
      {videoFiles > 0 && (
        <UploadSection
          type="video"
          urls={cv.videoUrls}
          maxCount={videoFiles}
          maxSizeMb={Math.max(maxSizeMb, 100)}
          disabled={disabled ?? false}
          icon={<VideoCameraOutlined />}
          label="参考视频"
          customRequest={customRequest}
          onChange={(urls) => emit({ videoUrls: urls })}
          previewContextMenu={imageMenuItems}
        />
      )}

      {/* 参考音频上传 */}
      {audioFiles > 0 && (
        <UploadSection
          type="audio"
          urls={cv.audioUrls}
          maxCount={audioFiles}
          maxSizeMb={maxSizeMb}
          disabled={disabled ?? false}
          icon={<AudioOutlined />}
          label="参考音频"
          customRequest={customRequest}
          onChange={(urls) => emit({ audioUrls: urls })}
          previewContextMenu={imageMenuItems}
        />
      )}
    </div>
      </ContextMenu>
  );
}
