import { ref } from 'vue'
import hookFetch from 'hook-fetch'
import { sseTextDecoderPlugin } from 'hook-fetch/plugins/sse'
import type { ChatSseMessage } from '../types'

const api = hookFetch.create({
	baseURL: '',
	timeout: 0,
	headers: {
		'Content-Type': 'application/json;charset=utf-8'
	}
})
api.use(sseTextDecoderPlugin({ json: false }))

export function useChatStream() {
	const isLoading = ref(false)
	let abortController: AbortController | null = null

	const cancelRequest = () => {
		if (abortController) {
			abortController.abort()
			abortController = null
		}
		isLoading.value = false
	}

	const parseSseBlock = (block: string): ChatSseMessage[] => {
		const dataLines = block
			.split(/\r?\n/)
			.filter((line) => line.startsWith('data:'))
			.map((line) => line.replace(/^data:\s?/, ''))

		if (!dataLines.length) {
			const text = block.trim()
			return text ? [{ response_type: 'answer', content: text, done: false }] : []
		}

		const data = dataLines.join('\n').trim()
		if (!data || data === '[DONE]') {
			return [{ response_type: 'complete', done: true }]
		}

		try {
			return [JSON.parse(data)]
		} catch {
			return [{ response_type: 'answer', content: data, done: false }]
		}
	}

	const normalizeRequestError = async (error: any) => {
		if (!error) return new Error('Unknown error')
		if (error instanceof Error) return error

		const message =
			error?.error ||
			error?.message ||
			error?.msg ||
			(error?.status ? `HTTP error! status: ${error.status}` : 'Request failed')

		return new Error(message)
	}

	const streamChat = async (
		url: string,
		body: any,
		onChunk: (chunk: ChatSseMessage) => void,
		onComplete: () => void,
		onError: (err: Error) => void
	) => {
		isLoading.value = true
		abortController = new AbortController()

		try {
			const token =
				localStorage.getItem('oauth2token') ||
				document.cookie.match(new RegExp('(^| )' + 'x-sessionId_b' + '=([^;]*)(;|$)'))?.[2]

			// dev读取环境变量 prod使用当前
			const baseUrl = import.meta.env.DEV ? `http://${import.meta.env.VITE_BASE_URL}` : ''

			const request = api.post(baseUrl + url, body, {
				signal: abortController.signal,
				headers: {
					Authorization: token ? JSON.parse(token) : ''
				}
			})

			for await (const chunk of request.stream<string>()) {
				if (chunk.error) {
					throw await normalizeRequestError(chunk.error)
				}

				const result = `${chunk.result ?? ''}`
				if (!result.trim()) continue

				parseSseBlock(result).forEach(onChunk)
			}

			onComplete()
		} catch (error: any) {
			if (error?.name !== 'AbortError') {
				onError(await normalizeRequestError(error))
			}
		} finally {
			isLoading.value = false
			abortController = null
		}
	}

	return {
		isLoading,
		cancelRequest,
		streamChat
	}
}
