import type { ChatMessage } from '/$/agent/types/index.d';

type ChatRole = ChatMessage['role'];

function parseJson(value: unknown): unknown {
	if (typeof value !== 'string') return value;
	try {
		return JSON.parse(value);
	} catch {
		return value;
	}
}

function stringifyContent(value: unknown): string {
	if (value == null) return '';
	if (typeof value === 'string') return value;
	if (Array.isArray(value)) {
		return value.map((item) => {
			if (typeof item === 'string') return item;
			if (item && typeof item === 'object') {
				const obj = item as Record<string, any>;
				return obj.text || obj.content || obj.value || JSON.stringify(item);
			}
			return String(item);
		}).filter(Boolean).join('\n');
	}
	try {
		return JSON.stringify(value, null, 2);
	} catch {
		return String(value);
	}
}

function inferRole(raw: any): ChatRole {
	const rawId = Array.isArray(raw?.id) ? raw.id[raw.id.length - 1] : raw?.id;
	const role = String(
		raw?.role ||
		raw?.type ||
		raw?.message?.role ||
		raw?.kwargs?.role ||
		rawId ||
		''
	).toLowerCase();

	if (['user', 'human', 'humanmessage'].includes(role)) return 'user';
	if (['assistant', 'ai', 'aimessage'].includes(role)) return 'assistant';
	if (['tool', 'toolmessage', 'function'].includes(role)) return 'tool';
	if (['system', 'systemmessage'].includes(role)) return 'system';
	if (['clarify'].includes(role)) return 'clarify';
	if (['compaction'].includes(role)) return 'compaction';
	return 'assistant';
}

function normalizeMetadata(raw: any): any {
	const parsed = parseJson(raw?.metadata);
	const metadata = parsed && typeof parsed === 'object' ? { ...(parsed as Record<string, any>) } : {};
	const kwargs = raw?.kwargs && typeof raw.kwargs === 'object' ? raw.kwargs : {};
	const additional = kwargs.additional_kwargs || {};
	const response = kwargs.response_metadata || raw?.response_metadata;

	if (raw?.tokenUsage && !metadata.tokenUsage) metadata.tokenUsage = raw.tokenUsage;
	if (raw?.usage && !metadata.tokenUsage) metadata.tokenUsage = raw.usage;
	if (additional?.tokenUsage && !metadata.tokenUsage) metadata.tokenUsage = additional.tokenUsage;
	if (response?.tokenUsage && !metadata.tokenUsage) metadata.tokenUsage = response.tokenUsage;
	if (raw?.skillExecutions && !metadata.skillExecutions) metadata.skillExecutions = raw.skillExecutions;
	if (additional?.skillExecutions && !metadata.skillExecutions) metadata.skillExecutions = additional.skillExecutions;

	return Object.keys(metadata).length ? metadata : undefined;
}

function normalizeContent(content: unknown): string {
	return stringifyContent(parseJson(content)).replace(/\/open\/agent\/workspace\/file/g, '/open/netaclaw/workspace/file');
}

function normalizeOne(raw: any): ChatMessage | null {
	if (!raw) return null;
	const source = raw.message && typeof raw.message === 'object' ? { ...raw.message, timestamp: raw.timestamp } : raw;
	const kwargs = source.kwargs && typeof source.kwargs === 'object' ? source.kwargs : {};
	const role = inferRole(source);
	const content = normalizeContent(source.content ?? source.text ?? kwargs.content ?? source.data?.content);
	const thinking = normalizeContent(source.thinking ?? kwargs.additional_kwargs?.thinking ?? '');
	const metadata = normalizeMetadata(source);

	if (!content && !thinking && !metadata?.skillExecutions?.length && !source.skillName) return null;

	return {
		id: source.id,
		sessionId: source.sessionId,
		role,
		content,
		thinking: thinking || undefined,
		skillName: source.skillName || kwargs.name,
		toolCalls: source.toolCalls || kwargs.tool_calls || kwargs.additional_kwargs?.tool_calls,
		metadata,
		createTime: source.createTime || source.updateTime || source.timestamp,
	};
}

function pickMessageArray(payload: any): any[] {
	if (Array.isArray(payload)) return payload;
	if (Array.isArray(payload?.messages)) return payload.messages;
	if (Array.isArray(payload?.list)) return payload.list;
	if (Array.isArray(payload?.records)) return payload.records;
	if (Array.isArray(payload?.entries)) return payload.entries;
	if (Array.isArray(payload?.activePath)) return payload.activePath;
	return [];
}

export function normalizeChatMessages(payload: unknown): ChatMessage[] {
	return pickMessageArray(payload)
		.map(normalizeOne)
		.filter((item): item is ChatMessage => Boolean(item));
}
