import { useCallback, useEffect, useRef, useState } from "react";
import type { Message } from "../types";

const STORAGE_KEY_PREFIX = "storykit-chat-history:";
const LIMIT_KEY_PREFIX = "storykit-chat-history-limit:";
const DEFAULT_LIMIT = 200;

function storageKey(projectPath: string): string {
	return `${STORAGE_KEY_PREFIX}${projectPath}`;
}

function limitKey(projectPath: string): string {
	return `${LIMIT_KEY_PREFIX}${projectPath}`;
}

function loadLimit(projectPath: string): number {
	try {
		const raw = localStorage.getItem(limitKey(projectPath));
		if (raw === null) return DEFAULT_LIMIT;
		const parsed = Number(raw);
		if (!Number.isFinite(parsed) || parsed < 0) return DEFAULT_LIMIT;
		return Math.floor(parsed);
	} catch {
		return DEFAULT_LIMIT;
	}
}

function saveLimit(projectPath: string, limit: number): void {
	try {
		localStorage.setItem(limitKey(projectPath), String(limit));
	} catch {
		// Ignore — quota or security errors.
	}
}

function loadMessages(projectPath: string): Message[] {
	try {
		const raw = localStorage.getItem(storageKey(projectPath));
		if (!raw) return [];
		const parsed: unknown = JSON.parse(raw);
		if (!Array.isArray(parsed)) return [];
		return parsed as Message[];
	} catch {
		return [];
	}
}

function pruneMessages(messages: Message[], limit: number): Message[] {
	if (limit === 0 || messages.length <= limit) return messages;
	return messages.slice(-limit);
}

function saveMessages(
	projectPath: string,
	messages: Message[],
	limit: number,
): void {
	try {
		const pruned = pruneMessages(messages, limit);
		if (pruned.length === 0) {
			localStorage.removeItem(storageKey(projectPath));
		} else {
			localStorage.setItem(storageKey(projectPath), JSON.stringify(pruned));
		}
	} catch (e) {
		console.warn("Failed to persist chat history to localStorage:", e);
	}
}

export function useChatHistory(projectPath: string) {
	const [messages, setMessagesState] = useState<Message[]>(() =>
		loadMessages(projectPath),
	);
	const [maxMessages, setMaxMessagesState] = useState<number>(() =>
		loadLimit(projectPath),
	);
	const projectPathRef = useRef(projectPath);

	// Keep the ref in sync so the effect closure always has the latest path.
	projectPathRef.current = projectPath;

	// Persist whenever messages or limit change.
	useEffect(() => {
		saveMessages(projectPathRef.current, messages, maxMessages);
	}, [messages, maxMessages]);

	const setMessages = useCallback(
		(update: Message[] | ((prev: Message[]) => Message[])) => {
			setMessagesState(update);
		},
		[],
	);

	const setMaxMessages = useCallback((limit: number) => {
		setMaxMessagesState(limit);
		saveLimit(projectPathRef.current, limit);
	}, []);

	const clearMessages = useCallback(() => {
		setMessagesState([]);
		// Eagerly remove from storage so clearSession doesn't depend on the
		// effect firing before the component unmounts or re-renders.
		try {
			localStorage.removeItem(storageKey(projectPathRef.current));
		} catch {
			// Ignore — quota or security errors.
		}
	}, []);

	return {
		messages,
		setMessages,
		clearMessages,
		maxMessages,
		setMaxMessages,
	} as const;
}
