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

import { downloadFileFromBlob } from '@easyflow/utils';

import { api } from '#/api/request';

const DOCUMENT_URL_REVOKE_DELAY_MS = 1000;

export type AgentComposerMode = 'DRAFT' | 'FORMAL';

export type AgentArtifactDownloadContext =
  | {
      agentId: string;
      mode: 'DRAFT';
      runtimeSessionId: string;
    }
  | {
      agentId: string;
      mode: 'FORMAL';
      sessionId: string;
    };

export interface AgentMediaUpload extends ChatImageAttachment {
  expiresAt?: string;
  height: number;
  mimeType: string;
  name: string;
  previewUrl: string;
  size: number;
  uploadId: string;
  width: number;
}

export interface AgentDocumentUpload extends ChatDocumentAttachment {
  expiresAt?: string;
  status: 'error' | 'reading' | 'ready' | 'uploading';
  uploadId: string;
}

export interface AgentComposerDraftPayload {
  agentId: string;
  documentUploadIds: string[];
  documents?: AgentDocumentUpload[];
  expiresAt?: string;
  imageUploadIds: string[];
  images?: AgentMediaUpload[];
  mode: AgentComposerMode;
  revision: number;
  sessionId: string;
  text: string;
}

interface RequestResult<T = any> {
  data: T;
  errorCode: number;
  message?: string;
}

export function allocateAgentComposerSession(mode: AgentComposerMode) {
  return api.post<
    RequestResult<{ mode: AgentComposerMode; sessionId: string }>
  >('/api/v1/agent/composer/session', { mode });
}

export function uploadAgentChatImage(
  file: File,
  context: {
    agentId: string;
    mode: AgentComposerMode;
    sessionId: string;
  },
) {
  const body = new FormData();
  body.append('file', file);
  body.append('mode', context.mode);
  body.append('agentId', context.agentId);
  body.append('sessionId', context.sessionId);
  return api.postFile<RequestResult<AgentMediaUpload>>(
    '/api/v1/agent/media/upload',
    body,
  );
}

export function deleteAgentChatImage(uploadId: string) {
  return api.post<RequestResult<void>>('/api/v1/agent/media/delete', {
    uploadId,
  });
}

export function uploadAgentChatDocument(
  file: File,
  context: {
    agentId: string;
    mode: AgentComposerMode;
    sessionId: string;
  },
  uploadId?: string,
) {
  const body = new FormData();
  body.append('file', file);
  body.append('mode', context.mode);
  body.append('agentId', context.agentId);
  body.append('sessionId', context.sessionId);
  if (uploadId) {
    body.append('uploadId', uploadId);
  }
  return api.postFile<RequestResult<AgentDocumentUpload>>(
    '/api/v1/agent/media/document/upload',
    body,
  );
}

export function getAgentChatDocumentStatus(uploadId: string) {
  return api.get<RequestResult<AgentDocumentUpload>>(
    '/api/v1/agent/media/document/status',
    { params: { uploadId } },
  );
}

export function retryAgentChatDocument(uploadId: string) {
  return api.post<RequestResult<AgentDocumentUpload>>(
    '/api/v1/agent/media/document/retry',
    { uploadId },
  );
}

export function deleteAgentChatDocument(uploadId: string) {
  return api.post<RequestResult<void>>('/api/v1/agent/media/document/delete', {
    uploadId,
  });
}

export function getAgentComposerDraft(params: {
  agentId: string;
  mode: AgentComposerMode;
  sessionId?: string;
}) {
  return api.get<RequestResult<AgentComposerDraftPayload | null>>(
    '/api/v1/agent/composer/draft',
    { params },
  );
}

export function saveAgentComposerDraft(data: AgentComposerDraftPayload) {
  return api.post<RequestResult<AgentComposerDraftPayload>>(
    '/api/v1/agent/composer/draft/persist',
    data,
  );
}

export function deleteAgentComposerDraft(data: {
  agentId: string;
  deleteUploads?: boolean;
  documentUploadIds?: string[];
  imageUploadIds?: string[];
  mode: AgentComposerMode;
  sessionId: string;
}) {
  return api.post<RequestResult<void>>(
    '/api/v1/agent/composer/draft/delete',
    data,
  );
}

export async function loadAgentChatImage(previewUrl: string) {
  if (!previewUrl || /^(?:blob:|data:)/i.test(previewUrl)) return previewUrl;
  const blob = await api.download<Blob>(previewUrl);
  return URL.createObjectURL(blob);
}

export async function loadAgentChatDocument(item: ChatDocumentAttachment) {
  if (!item.downloadUrl) return;
  const blob = await api.download<Blob>(item.downloadUrl);
  if (!(blob instanceof Blob) || blob.size <= 0) {
    throw new Error('下载内容为空，请稍后重试');
  }
  const url = URL.createObjectURL(blob);
  const anchor = document.createElement('a');
  anchor.href = url;
  anchor.download = item.name || '文档';
  try {
    document.body.append(anchor);
    anchor.click();
  } finally {
    anchor.remove();
    window.setTimeout(() => {
      URL.revokeObjectURL(url);
    }, DOCUMENT_URL_REVOKE_DELAY_MS);
  }
}

export function createAgentArtifactLoader(
  resolveContext: () => AgentArtifactDownloadContext | undefined,
): ChatArtifactLoader {
  return async (item) => {
    const downloadUrl = buildAgentArtifactDownloadUrl(
      item.artifactId,
      resolveContext(),
    );
    const blob = await api.download<Blob>(downloadUrl);
    if (!(blob instanceof Blob)) {
      throw new TypeError('产物下载失败，请重试');
    }
    downloadFileFromBlob({ fileName: item.fileName || '产物', source: blob });
  };
}

function buildAgentArtifactDownloadUrl(
  artifactIdValue: string,
  context: AgentArtifactDownloadContext | undefined,
) {
  const artifactId = String(artifactIdValue || '').trim();
  if (!artifactId || !context) {
    throw new TypeError('产物下载上下文无效');
  }
  const agentId = String(context.agentId || '').trim();
  if (!/^[1-9]\d*$/.test(agentId)) {
    throw new TypeError('产物下载上下文无效');
  }

  const params = new URLSearchParams({ agentId, mode: context.mode });
  if (context.mode === 'DRAFT') {
    const runtimeSessionId = String(context.runtimeSessionId || '').trim();
    if (!runtimeSessionId) {
      throw new TypeError('产物下载上下文无效');
    }
    params.set('runtimeSessionId', runtimeSessionId);
  } else {
    const sessionId = String(context.sessionId || '').trim();
    if (!sessionId) {
      throw new TypeError('产物下载上下文无效');
    }
    params.set('sessionId', sessionId);
  }

  return `/api/v1/agent/artifacts/${encodeURIComponent(artifactId)}/content?${params.toString()}`;
}
