import { computed, watch } from 'vue';
import { defineStore } from 'pinia';
import { STORES } from '@n8n/stores';
import { useUIStore } from '@/app/stores/ui.store';
import { useRoute } from 'vue-router';
import {
	ASK_AI_SLIDE_IN_DURATION_MS,
	ASK_AI_SLIDE_OUT_DURATION_MS,
	EDITABLE_CANVAS_VIEWS,
} from '@/app/constants';
import type { VIEWS } from '@/app/constants';
import { ASSISTANT_ENABLED_VIEWS, BUILDER_ENABLED_VIEWS } from './constants';
import { useChatPanelStateStore, type ChatPanelMode } from './chatPanelState.store';
import { useAssistantStore } from './assistant.store';
import { useBuilderStore } from './builder.store';
import { useSettingsStore } from '@/app/stores/settings.store';
import { useWorkflowsStore } from '@/app/stores/workflows.store';
import { usePostHog } from '@/app/stores/posthog.store';
import { MERGE_ASK_BUILD_EXPERIMENT } from '@/app/constants/experiments';
import type { ICredentialType } from 'n8n-workflow';
import type { ChatRequest } from './assistant.types';
import { useI18n } from '@n8n/i18n';

export const MAX_CHAT_WIDTH = 425;
export const MIN_CHAT_WIDTH = 380;
export const DEFAULT_CHAT_WIDTH = 400;

/**
 * Type guard to check if a route name is a valid VIEWS value within the enabled views
 * Performs runtime validation to safely narrow the type without unsafe assertions
 */
function isEnabledView(
	route: string | symbol | undefined,
	views: readonly VIEWS[],
): route is VIEWS {
	return typeof route === 'string' && (views as readonly string[]).includes(route);
}

export const useChatPanelStore = defineStore(STORES.CHAT_PANEL, () => {
	const uiStore = useUIStore();
	const route = useRoute();
	const chatPanelStateStore = useChatPanelStateStore();
	const settingsStore = useSettingsStore();
	const workflowsStore = useWorkflowsStore();
	const posthogStore = usePostHog();
	const locale = useI18n();

	let openTimerId: ReturnType<typeof setTimeout> | null = null;

	const isMergeAskBuildEnabled = computed(
		() =>
			posthogStore.isFeatureEnabled(MERGE_ASK_BUILD_EXPERIMENT.name) &&
			settingsStore.isAiAssistantEnabled &&
			useBuilderStore().isAIBuilderEnabled,
	);

	/** When merge is enabled, redirect assistant mode requests to builder */
	function resolveMode(mode: ChatPanelMode): ChatPanelMode {
		return mode === 'assistant' && isMergeAskBuildEnabled.value ? 'builder' : mode;
	}

	// Computed
	const isAssistantModeActive = computed(() => chatPanelStateStore.activeMode === 'assistant');
	const isBuilderModeActive = computed(() => chatPanelStateStore.activeMode === 'builder');

	const isEditableCanvasView = computed(() => EDITABLE_CANVAS_VIEWS.includes(route.name as VIEWS));

	// Actions
	async function open(options?: { mode?: ChatPanelMode; showCoachmark?: boolean }) {
		if (!settingsStore.isAiAssistantOrBuilderEnabled) return;

		const mode = options?.mode ? resolveMode(options.mode) : undefined;
		const showCoachmark = options?.showCoachmark ?? true;

		if (mode) {
			chatPanelStateStore.activeMode = mode;
		}
		chatPanelStateStore.showCoachmark = showCoachmark;

		// Check if the mode is enabled in the current view
		const enabledViews =
			chatPanelStateStore.activeMode === 'assistant'
				? ASSISTANT_ENABLED_VIEWS
				: BUILDER_ENABLED_VIEWS;
		const currentRoute = route?.name;

		if (!isEnabledView(currentRoute, enabledViews)) {
			// Mode is not enabled in current view, close the panel instead
			close();
			return;
		}

		chatPanelStateStore.isOpen = true;

		if (chatPanelStateStore.activeMode === 'builder') {
			const builderStore = useBuilderStore();
			if (!builderStore.streaming) {
				void builderStore.fetchBuilderCredits();
				void builderStore.loadSessions();
			}
		} else if (chatPanelStateStore.activeMode === 'assistant') {
			const assistantStore = useAssistantStore();
			assistantStore.chatMessages = assistantStore.chatMessages.map((msg) => ({
				...msg,
				read: true,
			}));
		}
		// Wait for slide animation to finish before updating grid width
		if (openTimerId) clearTimeout(openTimerId);
		openTimerId = setTimeout(() => {
			openTimerId = null;
			uiStore.appGridDimensions = {
				...uiStore.appGridDimensions,
				width: window.innerWidth - chatPanelStateStore.width,
			};
		}, ASK_AI_SLIDE_IN_DURATION_MS);
	}

	function close() {
		if (openTimerId) {
			clearTimeout(openTimerId);
			openTimerId = null;
		}
		chatPanelStateStore.isOpen = false;
		chatPanelStateStore.showCoachmark = false;
		// Wait for slide animation to finish before updating grid width and resetting
		setTimeout(() => {
			uiStore.appGridDimensions = {
				...uiStore.appGridDimensions,
				width: window.innerWidth,
			};

			const assistantStore = useAssistantStore();

			// Reset assistant only if session has ended
			if (assistantStore.isSessionEnded) {
				assistantStore.resetAssistantChat(workflowsStore.workflowId);
			}
		}, ASK_AI_SLIDE_OUT_DURATION_MS + 50);
	}

	async function toggle(options?: { mode?: ChatPanelMode }) {
		if (chatPanelStateStore.isOpen) {
			close();
		} else {
			await open(options);
		}
	}

	function switchMode(mode: ChatPanelMode) {
		const resolved = resolveMode(mode);

		// Check if the mode is enabled in the current view
		const enabledViews = resolved === 'assistant' ? ASSISTANT_ENABLED_VIEWS : BUILDER_ENABLED_VIEWS;
		const currentRoute = route?.name;

		if (!isEnabledView(currentRoute, enabledViews)) {
			// Mode is not enabled in current view, close the panel
			close();
			return;
		}

		// Switch the mode without re-initialization
		chatPanelStateStore.activeMode = resolved;
		chatPanelStateStore.showCoachmark = false;
	}

	function updateWidth(newWidth: number) {
		const clampedWidth = Math.min(Math.max(newWidth, MIN_CHAT_WIDTH), MAX_CHAT_WIDTH);
		chatPanelStateStore.width = clampedWidth;
		if (chatPanelStateStore.isOpen) {
			uiStore.appGridDimensions = {
				...uiStore.appGridDimensions,
				width: window.innerWidth - clampedWidth,
			};
		}
	}

	/**
	 * Opens assistant with credential help context
	 */
	async function openWithCredHelp(credentialType: ICredentialType) {
		if (isMergeAskBuildEnabled.value) {
			const question = locale.baseText('aiAssistant.builder.credentialHelpMessage', {
				interpolate: { credentialName: credentialType.displayName },
			});
			await open({ mode: 'builder' });
			const builderStore = useBuilderStore();
			await builderStore.sendChatMessage({ text: question, helpMessage: true });
			return;
		}
		const assistantStore = useAssistantStore();
		await assistantStore.initCredHelp(workflowsStore.workflowId, credentialType);
		await open({ mode: 'assistant' });
	}

	/**
	 * Opens assistant with error helper context
	 */
	async function openWithErrorHelper(context: ChatRequest.ErrorContext) {
		if (isMergeAskBuildEnabled.value) {
			const errorText = locale.baseText('aiAssistant.builder.errorHelpMessage', {
				interpolate: { nodeName: context.node.name, errorMessage: context.error.message },
			});
			await open({ mode: 'builder' });
			const builderStore = useBuilderStore();
			await builderStore.sendChatMessage({ text: errorText, helpMessage: true });
			return;
		}
		const assistantStore = useAssistantStore();
		await assistantStore.initErrorHelper(workflowsStore.workflowId, context);
		await open({ mode: 'assistant' });
	}

	// Watch route changes and close if panel can't be shown in current view
	watch(
		() => route?.name,
		(newRoute) => {
			if (!newRoute) {
				return;
			}

			const builderStore = useBuilderStore();

			// Re-open panel if streaming and entering a builder view
			if (
				!chatPanelStateStore.isOpen &&
				builderStore.streaming &&
				isEnabledView(newRoute, BUILDER_ENABLED_VIEWS)
			) {
				void open({ mode: 'builder' });
				return;
			}

			if (!chatPanelStateStore.isOpen) {
				return;
			}

			const enabledViews =
				chatPanelStateStore.activeMode === 'assistant'
					? ASSISTANT_ENABLED_VIEWS
					: BUILDER_ENABLED_VIEWS;

			if (!isEnabledView(newRoute, enabledViews)) {
				close();
			} else if (isEnabledView(newRoute, BUILDER_ENABLED_VIEWS) && !builderStore.streaming) {
				builderStore.resetBuilderChat();
			}
		},
	);

	return {
		// State - expose from chatPanelStateStore
		isOpen: computed(() => chatPanelStateStore.isOpen),
		width: computed(() => chatPanelStateStore.width),
		activeMode: computed(() => chatPanelStateStore.activeMode),
		showCoachmark: computed(() => chatPanelStateStore.showCoachmark),
		// Computed
		isAssistantModeActive,
		isBuilderModeActive,
		isEditableCanvasView,
		// Actions
		open,
		close,
		toggle,
		switchMode,
		updateWidth,
		openWithCredHelp,
		openWithErrorHelper,
		// Constants
		DEFAULT_CHAT_WIDTH,
		MIN_CHAT_WIDTH,
		MAX_CHAT_WIDTH,
	};
});
