import { nextTick, onMounted, type Ref, watch } from 'vue';
import type { ElScrollbar } from 'element-plus';
import type { LocationQuery } from 'vue-router';
import type { AgentInfo, StreamingToolProjection } from '../types/index.d';

type ChatLifecycleRefs = {
	agents: Ref<AgentInfo[]>;
	composerPrefill: Ref<string>;
	currentAgentId: Ref<number | null>;
	inputContent: Ref<string>;
	loading: Ref<boolean>;
	scrollbarRef: Ref<InstanceType<typeof ElScrollbar> | undefined>;
	streamingAssistantText: Ref<string>;
	streamingAssistantThinking: Ref<string>;
	streamingTools: Ref<StreamingToolProjection[]>;
	visibleConversationEntries: Ref<unknown[]>;
};

type ChatLifecycleOperations = {
	init: () => Promise<unknown>;
	loadAgents: () => Promise<unknown>;
	loadSessions: () => Promise<unknown>;
	newSession: () => void;
	selectAgent: (agentId: number) => Promise<unknown>;
	switchSession?: (sessionId: string) => Promise<unknown>;
};

const AUTO_SCROLL_BOTTOM_THRESHOLD = 96;

function getScrollbarWrap(scrollbar: InstanceType<typeof ElScrollbar> | undefined): HTMLElement | null {
	return ((scrollbar as any)?.wrapRef || null) as HTMLElement | null;
}

function isNearBottom(scrollbar: InstanceType<typeof ElScrollbar> | undefined) {
	const wrap = getScrollbarWrap(scrollbar);
	if (!wrap) return true;
	return wrap.scrollHeight - wrap.scrollTop - wrap.clientHeight <= AUTO_SCROLL_BOTTOM_THRESHOLD;
}

export function useChatLifecycle(refs: ChatLifecycleRefs, operations: ChatLifecycleOperations, query: LocationQuery) {
	async function applyRouteSelection() {
		const queryAgentId = query.agentId;
		if (queryAgentId) {
			const id = Number(queryAgentId);
			if (!Number.isNaN(id) && id !== refs.currentAgentId.value) {
				await operations.selectAgent(id);
				operations.newSession();
			}
		}

		const rawSessionId = query.sessionId;
		if (typeof rawSessionId === 'string' && rawSessionId.trim() && operations.switchSession) {
			try {
				await operations.switchSession(rawSessionId.trim());
			} catch {
				// ignore — session may not exist yet
			}
		}
	}

	watch(refs.composerPrefill, value => {
		if (value) refs.inputContent.value = value;
	});

	watch(
		() => [
			refs.visibleConversationEntries.value.length,
			refs.streamingAssistantText.value,
			refs.streamingAssistantThinking.value,
			refs.streamingTools.value.length,
			refs.loading.value,
		],
		() => {
			const shouldFollowOutput = isNearBottom(refs.scrollbarRef.value);
			void nextTick(() => {
				if (shouldFollowOutput) {
					refs.scrollbarRef.value?.setScrollTop(999999);
				}
			});
		}
	);

	watch(
		() => [query.agentId, query.sessionId],
		() => {
			void applyRouteSelection();
		}
	);

	onMounted(async () => {
		await operations.init();

		if (refs.agents.value.length === 0) {
			await operations.loadAgents();
		}

		await operations.loadSessions();
		await applyRouteSelection();
	});
}
