/* eslint-disable */
// @ts-ignore
import type { CustomRequestOptions } from '@/http/types';

type AnyRecord = Record<string, any>;

type StreamCallbacks = {
  onToken?: (text: string) => void;
  onDone?: () => void;
  onError?: (err: unknown) => void;
  onStart?: (payload: Record<string, any>) => void;
  onTool?: (payload: Record<string, any>) => void;
  onChunk?: (payload: Record<string, any>) => void;
  onEnd?: (payload: Record<string, any>) => void;
};

export type AiChatStreamQuery = {
  content: string;
  conversationId?: string;
};

function decodeChunk(data: ArrayBuffer | string): string {
  if (typeof data === 'string') return data;
  try {
    return new TextDecoder('utf-8').decode(data);
  } catch (e) {
    const arr = new Uint8Array(data);
    let str = '';
    for (let i = 0; i < arr.length; i += 1) str += String.fromCharCode(arr[i]);
    return decodeURIComponent(escape(str));
  }
}

function parseSsePayload(raw: string): string {
  const line = raw.trim();
  if (!line) return '';
  if (!line.startsWith('data:')) return line;
  const payload = line.slice(5).trim();
  if (!payload || payload === '[DONE]') return '';
  try {
    const json = JSON.parse(payload);
    return (
      json?.content ??
      json?.delta?.content ??
      json?.message ??
      json?.data?.content ??
      ''
    );
  } catch (e) {
    return payload;
  }
}

function parseSseEventBlock(block: string): { event: string; payload: Record<string, any> | null } | null {
  const lines = block
    .split('\n')
    .map((line) => line.trim())
    .filter(Boolean);
  if (!lines.length) return null;

  let eventName = 'message';
  const dataLines: string[] = [];
  lines.forEach((line) => {
    if (line.startsWith('event:')) {
      eventName = line.slice(6).trim() || 'message';
    } else if (line.startsWith('data:')) {
      dataLines.push(line.slice(5).trim());
    }
  });

  if (!dataLines.length) return { event: eventName, payload: null };
  const raw = dataLines.join('\n');
  try {
    return { event: eventName, payload: JSON.parse(raw) };
  } catch (e) {
    return { event: eventName, payload: { text: raw } };
  }
}

function dispatchSseEvent(
  parsed: { event: string; payload: Record<string, any> | null } | null,
  callbacks?: StreamCallbacks,
) {
  if (!parsed) return;
  const payload = parsed.payload || {};
  switch (parsed.event) {
    case 'start':
      callbacks?.onStart?.(payload);
      break;
    case 'tool':
      callbacks?.onTool?.(payload);
      break;
    case 'chunk':
      callbacks?.onChunk?.(payload);
      if (!callbacks?.onChunk && typeof payload.text === 'string' && payload.text) {
        callbacks?.onToken?.(payload.text);
      }
      break;
    case 'end':
      callbacks?.onEnd?.(payload);
      callbacks?.onDone?.();
      break;
    default:
      // 兼容未知 event 或普通 message
      if (typeof payload.text === 'string' && payload.text) {
        callbacks?.onToken?.(payload.text);
      }
      break;
  }
}

/**
 * AI 流式对话 GET /app/ai/chat/stream
 * 注意：不同端对 chunk 支持程度不同，不支持时会在 success 中返回完整文本。
 */
export function appAiChatStreamGet({
  query,
  callbacks,
  options,
}: {
  query: AiChatStreamQuery;
  callbacks?: StreamCallbacks;
  options?: CustomRequestOptions;
}) {
  let buffer = '';
  let gotChunk = false;

  const task = uni.request({
    url: '/app/ai/chat/stream',
    method: 'GET',
    data: query,
    enableChunked: true as any,
    responseType: 'text',
    timeout: options?.timeout ?? 60000,
    header: {
      ...(options?.header || {}),
    },
    success(res) {
      // 部分端不支持 chunk 回调，这里兜底按整段文本处理
      if (gotChunk) {
        return;
      }
      const raw = typeof res.data === 'string' ? res.data : JSON.stringify(res.data || '');
      const normalized = raw.replace(/\r\n/g, '\n');
      const blocks = normalized.split('\n\n').filter(Boolean);
      if (!blocks.length) {
        if (raw) callbacks?.onToken?.(raw);
        callbacks?.onDone?.();
        return;
      }
      blocks.forEach((block) => {
        dispatchSseEvent(parseSseEventBlock(block), callbacks);
      });
    },
    fail(err) {
      callbacks?.onError?.(err);
    },
  });

  const taskAny = task as any;
  if (taskAny && typeof taskAny.onChunkReceived === 'function') {
    taskAny.onChunkReceived((chunk: { data: ArrayBuffer | string }) => {
      gotChunk = true;
      buffer += decodeChunk(chunk.data).replace(/\r\n/g, '\n');
      const blocks = buffer.split('\n\n');
      buffer = blocks.pop() || '';
      blocks.forEach((block) => {
        dispatchSseEvent(parseSseEventBlock(block), callbacks);
      });
    });
  }

  return task;
}

// 兼容旧调用名，避免其他页面引用报错
export const appAiChatStreamPost = appAiChatStreamGet;

