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 { useInputCallback } from "@common/hooks/useInputCallback";
import Prompt from "../utils/prompt";
import { BookOpen, List, Users, MapPin, BookMarked, FileText, Code, Layers, MessageSquare, type LucideIcon } from "lucide-preact";

const 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 },
];

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

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

    const handleScratchpadInput = useInputCallback((text: string) => {
        if (!currentStory) return;
        dispatch({ type: 'EDIT_SCRATCHPAD', id: currentStory.id, text });
    }, [currentStory?.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]);

    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, currentTab]);

    return (
        <div class={styles.editor}>
            {currentStory && <div class={styles.title}>{currentStory.title}</div>}
            <div class={clsx(styles.content, currentTab === 'menu' && styles.menuContent)} ref={contentRef}>
                {currentTab === "menu" && (
                    <Menu />
                )}
                {currentTab === "story" && currentStory && (
                    <ContentEditable
                        class={styles.editable}
                        value={storyValue}
                        onInput={handleInput}
                        placeholder="Start writing your story..."
                    />
                )}
                {currentTab === "lore" && currentStory && (
                    <LoreEditor />
                )}
                {currentTab === "characters" && currentStory && (
                    <CharacterEditor />
                )}
                {currentTab === "locations" && currentStory && (
                    <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 }} />
                )}
            </div>
            <div class={styles.tabs}>
                {TABS.filter(tab => currentStory || 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>
                ))}
                <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>
    );
};
