import { REASONING_EFFORT_LEVELS, REASONING_EFFORT_TOKENS } from '$lib/constants';
import { ReasoningEffort } from '$lib/enums';
import { conversationsStore, modelsStore, serverStore } from '$lib/stores';
import type { ReasoningEffortLevel } from '$lib/types';
import type { DatabaseMessage } from '$lib/types/database';
import { getConversationModel } from '$lib/utils';

export interface UseReasoningMenuReturn {
	readonly modelSupportsThinking: boolean;
	readonly thinkingEnabled: boolean;
	readonly isReasoningActive: boolean;
	readonly isOff: boolean;
	readonly currentEffort: ReasoningEffort;
	readonly levels: ReasoningEffortLevel[];
	isSelected(level: ReasoningEffortLevel): boolean;
	tokenLabel(level: ReasoningEffortLevel): string | null;
	select(level: ReasoningEffortLevel): void;
}

/**
 * Shared reactive state and helpers for the reasoning effort menu.
 *
 * Used by both the desktop dropdown (`ChatFormActionAddReasoningSubmenu`)
 * and the mobile sheet (`ChatFormActionAddSheet`) to avoid duplicating the
 * thinking-support derivation and the effort selection logic.
 */
export function useReasoningMenu(): UseReasoningMenuReturn {
	const conversationModel = $derived(
		getConversationModel(conversationsStore.activeMessages as DatabaseMessage[])
	);
	// a router chat can carry reasoning from an earlier turn before the props
	// cache is primed, so a model that already produced thinking still qualifies
	const modelSupportsThinkingFromMessages = $derived.by(() => {
		const modelId = serverStore.isRouterMode
			? modelsStore.selectedModelName || conversationModel
			: null;

		if (!modelId) return false;

		return conversationsStore.activeMessages.some(
			(m) => m.role === 'assistant' && m.model === modelId && !!m.reasoningContent
		);
	});
	const modelSupportsThinking = $derived.by(() => {
		void modelsStore.loadedModelIds;
		void modelsStore.props.cacheVersion;

		if (serverStore.isRouterMode) {
			const modelId = modelsStore.selectedModelName || conversationModel;

			return (
				modelsStore.props.checkModelSupportsThinking(modelId ?? '') ||
				modelSupportsThinkingFromMessages
			);
		}

		return modelsStore.props.supportsThinking || modelSupportsThinkingFromMessages;
	});
	const currentEffort = $derived(conversationsStore.preferences.getReasoningEffort());
	const thinkingEnabled = $derived(
		currentEffort !== ReasoningEffort.OFF && currentEffort !== ReasoningEffort.DEFAULT
	);
	// Thinking is effectively on (lightbulb lit) either when an explicit effort
	// is selected, or when the effort is left at "Default" and the model
	// supports thinking.
	const isReasoningActive = $derived(
		thinkingEnabled || (currentEffort === ReasoningEffort.DEFAULT && modelSupportsThinking)
	);

	return {
		get currentEffort() {
			return currentEffort;
		},
		get isOff() {
			return currentEffort === ReasoningEffort.OFF;
		},
		get isReasoningActive() {
			return isReasoningActive;
		},
		isSelected(level: ReasoningEffortLevel): boolean {
			return currentEffort === level.value;
		},
		get levels() {
			return REASONING_EFFORT_LEVELS;
		},
		get modelSupportsThinking() {
			return modelSupportsThinking;
		},
		select(level: ReasoningEffortLevel): void {
			conversationsStore.preferences.setReasoningEffort(level.value as ReasoningEffort);
		},
		get thinkingEnabled() {
			return thinkingEnabled;
		},
		tokenLabel(level: ReasoningEffortLevel): string | null {
			if (level.value === ReasoningEffort.DEFAULT) return 'Model default';

			const tokens = REASONING_EFFORT_TOKENS[level.value];

			if (tokens === undefined) return null;

			return tokens === -1 ? 'Unlimited' : `Max ${tokens.toLocaleString()} tokens`;
		}
	};
}
