import type { ChatImageAttachment } from '@easyflow/common-ui';

import { computed, ref } from 'vue';

import { deleteAgentChatImage, uploadAgentChatImage } from './mediaApi';
import type { AgentComposerMode, AgentMediaUpload } from './mediaApi';

const MAX_IMAGES = 5;
const MAX_IMAGE_BYTES = 10 * 1024 * 1024;
const ACCEPTED_EXTENSIONS = new Set([
  'bmp',
  'gif',
  'jpeg',
  'jpg',
  'png',
  'webp',
]);

interface UploadContext {
  agentId: string;
  mode: AgentComposerMode;
  sessionId: string;
}

interface LocalAttachment extends ChatImageAttachment {
  file?: File;
}

function createLocalId() {
  return `agent-image-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
}

function extensionOf(file: File) {
  const extension = file.name.includes('.')
    ? file.name.split('.').pop()?.toLowerCase() || ''
    : '';
  if (extension) return extension;
  return (
    {
      'image/bmp': 'bmp',
      'image/gif': 'gif',
      'image/jpeg': 'jpg',
      'image/png': 'png',
      'image/webp': 'webp',
    }[file.type.toLowerCase()] || ''
  );
}

function errorMessage(error: unknown) {
  const candidate = error as any;
  return (
    candidate?.response?.data?.message || candidate?.message || '图片上传失败'
  );
}

export function useChatImageUploads() {
  const items = ref<LocalAttachment[]>([]);
  const readyItems = computed(() =>
    items.value.filter(
      (item): item is LocalAttachment & AgentMediaUpload =>
        item.status === 'ready' && Boolean(item.uploadId),
    ),
  );
  const uploadIds = computed(() =>
    readyItems.value.map((item) => item.uploadId),
  );
  const uploading = computed(() =>
    items.value.some((item) => item.status === 'uploading'),
  );

  async function addFiles(files: File[], context: UploadContext) {
    const available = Math.max(0, MAX_IMAGES - items.value.length);
    const accepted = files.slice(0, available);
    const rejectedCount = Math.max(0, files.length - accepted.length);
    const uploads: Promise<void>[] = [];
    for (const file of accepted) {
      const extension = extensionOf(file);
      const local: LocalAttachment = {
        file,
        localId: createLocalId(),
        mimeType: file.type,
        name: file.name || '粘贴的图片',
        previewUrl: URL.createObjectURL(file),
        size: file.size,
        status: 'uploading',
      };
      items.value.push(local);
      if (!ACCEPTED_EXTENSIONS.has(extension)) {
        local.status = 'error';
        local.error = '仅支持 PNG、JPG、JPEG、WebP、GIF、BMP';
        continue;
      }
      if (file.size > MAX_IMAGE_BYTES) {
        local.status = 'error';
        local.error = '单张图片不能超过 10 MiB';
        continue;
      }
      uploads.push(upload(local, context));
    }
    await Promise.all(uploads);
    return rejectedCount;
  }

  async function upload(item: LocalAttachment, context: UploadContext) {
    if (!item.file) return;
    const current = items.value.find(
      (candidate) => candidate.localId === item.localId,
    );
    if (!current) return;
    current.status = 'uploading';
    current.error = undefined;
    try {
      const response = await uploadAgentChatImage(current.file!, context);
      if (response.errorCode !== 0 || !response.data) {
        throw new Error(response.message || '图片上传失败');
      }
      const latest = items.value.find(
        (candidate) => candidate.localId === item.localId,
      );
      if (!latest) {
        await deleteAgentChatImage(response.data.uploadId);
        return;
      }
      const localPreview = latest.previewUrl;
      Object.assign(latest, response.data, {
        file: latest.file,
        localId: latest.localId,
        status: 'ready',
      });
      if (localPreview.startsWith('blob:')) {
        URL.revokeObjectURL(localPreview);
      }
    } catch (error) {
      const latest = items.value.find(
        (candidate) => candidate.localId === item.localId,
      );
      if (latest) {
        latest.status = 'error';
        latest.error = errorMessage(error);
      }
    }
  }

  async function remove(item: ChatImageAttachment) {
    const index = items.value.findIndex(
      (candidate) =>
        candidate.localId === item.localId ||
        (candidate.uploadId && candidate.uploadId === item.uploadId),
    );
    if (index < 0) return;
    const selected = items.value[index];
    if (selected?.uploadId) {
      const response = await deleteAgentChatImage(selected.uploadId);
      if (response.errorCode !== 0) {
        throw new Error(response.message || '图片删除失败');
      }
    }
    const [removed] = items.value.splice(index, 1);
    if (removed?.previewUrl?.startsWith('blob:')) {
      URL.revokeObjectURL(removed.previewUrl);
    }
  }

  async function retry(item: ChatImageAttachment, context: UploadContext) {
    const found = items.value.find(
      (candidate) => candidate.localId === item.localId,
    );
    if (found?.file) {
      await upload(found, context);
    }
  }

  function restore(restored: AgentMediaUpload[] = []) {
    clear();
    items.value = restored.slice(0, MAX_IMAGES).map((item) => ({
      ...item,
      status: 'ready',
    }));
  }

  function clear() {
    for (const item of items.value) {
      if (item.previewUrl?.startsWith('blob:')) {
        URL.revokeObjectURL(item.previewUrl);
      }
    }
    items.value = [];
  }

  return {
    addFiles,
    clear,
    items,
    readyItems,
    remove,
    restore,
    retry,
    uploadIds,
    uploading,
  };
}
