import type {
	SubagentBatchEventProjection,
	SubagentRuntimeState,
	SessionTreeSubagentBatchMetadata,
	SessionTreeEntry,
	SessionTreeSubagentBatchContent,
	SessionTreeSubagentResultContent,
	ToolRuntimeRouteProjection,
} from '../types/index.d';

interface NormalizedSubagentBatchMetadata {
	events: SessionTreeSubagentBatchMetadata['events'] extends Array<infer T> ? T[] : never[];
	finalResults: Record<string, unknown>[];
	toolRuntimeRoutes: ToolRuntimeRouteProjection[];
}

export function getNormalizedSubagentBatchMetadata(entry: SessionTreeEntry): NormalizedSubagentBatchMetadata {
	const metadata = (entry.metadata || {}) as SessionTreeSubagentBatchMetadata;
	return {
		events: toBatchEventArray(metadata.events),
		finalResults: toRecordArray(metadata.finalResults),
		toolRuntimeRoutes: toToolRuntimeRouteArray(metadata.toolRuntimeRoutes),
	};
}

export function buildSubagentRuntimeMap(entries: SessionTreeEntry[]): Record<string, SubagentRuntimeState> {
	const next: Record<string, SubagentRuntimeState> = {};

	for (const entry of entries) {
		if (entry.type === 'subagent_batch') {
			const content = (entry.content || {}) as SessionTreeSubagentBatchContent;
			const metadata = getNormalizedSubagentBatchMetadata(entry);
			if (!content.batchId) continue;
			next[content.batchId] = {
				batchId: content.batchId,
				status: content.status === 'completed' ? 'completed' : 'running',
				mode: content.mode,
				tasks: Array.isArray(content.tasks) ? content.tasks : [],
				results: metadata.finalResults.length > 0 ? metadata.finalResults : next[content.batchId]?.results || [],
				events: metadata.events
					.map(item => toStoredSubagentRuntimeEvent(item))
					.filter((item): item is NonNullable<typeof item> => Boolean(item)),
			};
		}

		if (entry.type === 'subagent_result') {
			const content = (entry.content || {}) as SessionTreeSubagentResultContent;
			if (!content.batchId) continue;
			next[content.batchId] = {
				batchId: content.batchId,
				status: content.status === 'completed' ? 'completed' : 'running',
				mode: next[content.batchId]?.mode,
				tasks: next[content.batchId]?.tasks || [],
				results: Array.isArray(content.results) ? content.results : [],
				events: next[content.batchId]?.events || [],
			};
		}
	}

	return next;
}

export function extractToolRuntimeRoutesByBatch(entries: SessionTreeEntry[]): Record<string, ToolRuntimeRouteProjection[]> {
	const next: Record<string, ToolRuntimeRouteProjection[]> = {};

	for (const entry of entries) {
		if (entry.type !== 'subagent_batch') continue;
		const content = (entry.content || {}) as SessionTreeSubagentBatchContent;
		const metadata = getNormalizedSubagentBatchMetadata(entry);
		if (!content.batchId || metadata.toolRuntimeRoutes.length === 0) continue;
		next[content.batchId] = metadata.toolRuntimeRoutes;
	}

	return next;
}

function toRecordArray(value: unknown): Record<string, unknown>[] {
	if (!Array.isArray(value)) {
		return [];
	}

	return value.filter((item): item is Record<string, unknown> => Boolean(item) && typeof item === 'object' && !Array.isArray(item));
}

function toBatchEventArray(value: unknown): SubagentBatchEventProjection[] {
	if (!Array.isArray(value)) {
		return [];
	}

	return value
		.filter((item): item is SubagentBatchEventProjection => Boolean(item) && typeof item === 'object' && !Array.isArray(item))
		.map(item => ({ ...item }));
}

function toToolRuntimeRouteArray(value: unknown): ToolRuntimeRouteProjection[] {
	if (!Array.isArray(value)) {
		return [];
	}

	return value
		.filter((item): item is ToolRuntimeRouteProjection => Boolean(item) && typeof item === 'object' && !Array.isArray(item))
		.map(item => ({ ...item }));
}

function sanitizeRecord(value: unknown): Record<string, unknown> {
	if (!value || typeof value !== 'object' || Array.isArray(value)) {
		return { value };
	}

	return value as Record<string, unknown>;
}

function normalizeRuntimeTimestamp(value: unknown): number {
	if (typeof value === 'string') {
		const parsed = Date.parse(value);
		if (!Number.isNaN(parsed)) {
			return parsed;
		}
	}

	return Date.now();
}

function toStoredSubagentRuntimeEvent(value: unknown): SubagentRuntimeState['events'][number] | null {
	if (!value || typeof value !== 'object' || Array.isArray(value)) {
		return null;
	}

	const record = value as SubagentBatchEventProjection;
	const eventRecord = record.event && typeof record.event === 'object' && !Array.isArray(record.event)
		? record.event as Record<string, unknown>
		: {};

	return {
		timestamp: normalizeRuntimeTimestamp(record.timestamp),
		sequence: typeof record.sequence === 'number' ? record.sequence : undefined,
		kind: 'event',
		status: typeof eventRecord.status === 'string' ? eventRecord.status : undefined,
		payload: sanitizeRecord(eventRecord),
	};
}
