import { ContentEditable } from "@common/components/ContentEditable";
import { highlight } from "@common/highlight";
import { useAppState, type Tab } from "../contexts/state";
import styles from '../assets/editor.module.css';
import { useMemo, useRef, useEffect } from "preact/hooks";
import clsx from "clsx";
import { CharacterEditor } from "./character-editor";
import { LocationEditor } from "./location-editor";
import { ChaptersEditor } from "./chapters-editor";
import { LoreEditor } from "./lore-editor";
import { Menu } from "./menu";
import { ChatPanel } from "./chat-sidebar";
import { useInputCallback } from "@common/hooks/useInputCallback";
import Prompt from "../utils/prompt";
import { BookOpen, List, Users, MapPin, BookMarked, FileText, Code, Layers, MessageSquare, Globe, BrainCircuit, MessagesSquare, type LucideIcon } from "lucide-preact";

// Tabs available when a story is selected (regular world)
const STORY_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[] = [
    { id: "menu", label: "Menu", icon: List },
    { id: "story", label: "Story", icon: BookOpen },
    { id: "chapters", label: "Chapters", icon: Layers },
    { id: "lore", label: "Lore", icon: BookMarked },
    { id: "characters", label: "Characters", icon: Users },
    { id: "locations", label: "Locations", icon: MapPin },
    { id: "scratchpad", label: "Scratchpad", icon: FileText, right: true },
    { id: "prompt", label: "Prompt", icon: Code },
];

// Tabs available when only a world is selected (no story, regular world)
const WORLD_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[] = [
    { id: "menu", label: "Menu", icon: List },
    { id: "lore", label: "Lore", icon: BookMarked },
    { id: "characters", label: "Characters", icon: Users },
    { id: "locations", label: "Locations", icon: MapPin },
    { id: "system", label: "System", icon: BrainCircuit },
];

// Tabs for a chat session within a chat-only world
const CHAT_STORY_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[] = [
    { id: "menu", label: "Menu", icon: List },
    { id: "chat", label: "Chat", icon: MessageSquare },
    { id: "scratchpad", label: "Scratchpad", icon: FileText, right: true },
    { id: "prompt", label: "Prompt", icon: Code },
];

// Tabs for a chat-only world with no session selected
const CHAT_WORLD_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[] = [
    { id: "menu", label: "Menu", icon: List },
    { id: "system", label: "System", icon: BrainCircuit },
];

export const Editor = () => {
    const appState = useAppState();
    const { currentWorld, currentStory, currentTab, chatOpen, dispatch } = appState;

    const handleInput = useInputCallback((text: string) => {
        if (!currentStory || !currentWorld) return;
        dispatch({ type: 'EDIT_STORY', worldId: currentWorld.id, id: currentStory.id, text });
    }, [currentStory?.id, currentWorld?.id]);

    const handleScratchpadInput = useInputCallback((text: string) => {
        if (!currentStory || !currentWorld) return;
        dispatch({ type: 'EDIT_SCRATCHPAD', worldId: currentWorld.id, id: currentStory.id, text });
    }, [currentStory?.id, currentWorld?.id]);

    const handleSystemOverrideInput = useInputCallback((text: string) => {
        if (!currentWorld) return;
        dispatch({ type: 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE', worldId: currentWorld.id, systemInstructionOverride: text || undefined });
    }, [currentWorld?.id]);

    const handleTabChange = (tab: Tab) => {
        dispatch({ type: 'SET_CURRENT_TAB', tab });
    };

    const contentRef = useRef<HTMLDivElement>(null);

    const storyValue = useMemo(() => {
        if (!currentStory) return '';

        const { text, lastEditedText } = currentStory;
        if (!lastEditedText) return highlight(text);

        const idx = text.lastIndexOf(lastEditedText);
        if (idx === -1) return highlight(text);

        const marked = text.slice(0, idx) + '<mark>' + lastEditedText + '</mark>' + text.slice(idx + lastEditedText.length);

        return highlight(marked);
    }, [currentStory?.text, currentStory?.lastEditedText]);

    const scratchpadValue = useMemo(() => {
        return highlight(currentStory?.scratchpad || '');
    }, [currentStory?.scratchpad]);

    const promptPreview = useMemo(() => {
        if (currentTab !== 'prompt') return '';
        const text = Prompt.formatSystemPrompt(appState);
        return highlight(text, false);
    }, [currentTab, appState]);

    const overrideValue = useMemo(() => {
        return highlight(currentWorld?.systemInstructionOverride || '');
    }, [currentWorld?.systemInstructionOverride]);

    useEffect(() => {
        if (currentStory?.lastEditedText) {
            const raf = requestAnimationFrame(() => {
                if (contentRef.current) {
                    contentRef.current.scrollTo({
                        top: contentRef.current.scrollHeight,
                        behavior: 'smooth',
                    });
                }
            });
            return () => cancelAnimationFrame(raf);
        }
    }, [currentStory?.lastEditedText]);

    useEffect(() => {
        const raf = requestAnimationFrame(() => {
            if (contentRef.current) {
                contentRef.current.scrollTop = contentRef.current.scrollHeight;
            }
        });
        return () => cancelAnimationFrame(raf);
    }, [currentStory?.id, currentWorld?.id, currentTab]);

    const hasSelection = currentWorld !== null;
    const isChatOnly = currentWorld?.chatOnly ?? false;

    const tabs = currentStory
        ? (isChatOnly ? CHAT_STORY_TABS : STORY_TABS)
        : currentWorld
            ? (isChatOnly ? CHAT_WORLD_TABS : WORLD_TABS)
            : [{ id: "menu" as Tab, label: "Menu", icon: List }];

    // Title bar: use MessagesSquare icon for chat-only worlds
    const WorldIcon = isChatOnly ? MessagesSquare : Globe;
    const titleBar = currentStory
        ? <div class={styles.title}>
            <span class={styles.titleWorld}>{currentWorld?.title}</span>
            <span class={styles.titleSep}>/</span>{currentStory.title}</div>
        : currentWorld
            ? <div class={styles.title}><WorldIcon size={24} />{currentWorld.title}</div>
            : null;

    const isChatTab = currentTab === 'chat';

    return (
        <div class={styles.editor}>
            {titleBar}
            <div class={clsx(styles.content, currentTab === 'menu' && styles.menuContent, isChatTab && styles.chatContent)} ref={contentRef}>
                {currentTab === "menu" && (
                    <Menu />
                )}
                {currentTab === "story" && currentStory && (
                    <ContentEditable
                        class={styles.editable}
                        value={storyValue}
                        onInput={handleInput}
                        placeholder="Start writing your story..."
                    />
                )}
                {currentTab === "lore" && (currentStory || currentWorld) && (
                    <LoreEditor />
                )}
                {currentTab === "characters" && (currentStory || currentWorld) && (
                    <CharacterEditor />
                )}
                {currentTab === "locations" && (currentStory || currentWorld) && (
                    <LocationEditor />
                )}
                {currentTab === "chapters" && currentStory && (
                    <ChaptersEditor />
                )}
                {currentTab === "scratchpad" && currentStory && (
                    <ContentEditable
                        class={styles.editable}
                        value={scratchpadValue}
                        onInput={handleScratchpadInput}
                        placeholder="Notes, ideas, outlines — anything you don't want in the story..."
                    />
                )}
                {currentTab === "prompt" && currentStory && (
                    <div class={styles.promptPreview} dangerouslySetInnerHTML={{ __html: promptPreview }} />
                )}
                {currentTab === "system" && currentWorld && (
                    <ContentEditable
                        class={styles.editable}
                        value={overrideValue}
                        onInput={handleSystemOverrideInput}
                        placeholder="Override the global system instruction for this world. Leave empty to use the global setting."
                    />
                )}
                {currentTab === "chat" && currentStory && isChatOnly && (
                    <ChatPanel />
                )}
            </div>
            <div class={styles.tabs}>
                {tabs.filter(tab => hasSelection || tab.id === 'menu').map((tab) => (
                    <button
                        key={tab.id}
                        class={clsx(styles.tab, currentTab === tab.id && styles.active, tab.right && styles.tabRight)}
                        onClick={() => handleTabChange(tab.id)}
                        title={tab.label}
                    >
                        <tab.icon size={15} />
                        <span class={styles.tabLabel}>{tab.label}</span>
                    </button>
                ))}
                {currentStory && !isChatOnly && (
                    <button
                        class={clsx(styles.tab, styles.tabRight, chatOpen && styles.active)}
                        onClick={() => dispatch({ type: 'SET_CHAT_OPEN', open: !chatOpen })}
                        title="Chat"
                    >
                        <MessageSquare size={15} />
                        <span class={styles.tabLabel}>Chat</span>
                    </button>
                )}
            </div>
        </div>
    );
};
