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

// 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, right: true },
];

const CHAT_TAB = { id: "chat", label: "Chat", icon: MessageSquare } as const;
// 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 },
    CHAT_TAB,
    { id: "scratchpad", label: "Scratchpad", icon: FileText, right: true },
    { id: "system", label: "System", icon: BrainCircuit },
    { 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 handleTabChange = (tab: Tab) => {
        dispatch({ type: 'SET_CURRENT_TAB', tab });
    };

    const contentRef = useRef<HTMLDivElement>(null);
    const editorRef = useRef<HTMLDivElement>(null);

    const promptPreview = useMemo(() => {
        let text = Prompt.formatSystemPrompt(appState);
        text = Prompt.substituteVars(appState, text);
        return highlight(text, false);
    }, [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, currentWorld?.id, currentTab]);

    const isMobile = useMediaQuery(`(max-width: ${MOBILE_BREAKPOINT}px)`);

    useSwipeNavigation(
        editorRef,
        () => { // swipe left → next tab
            const idx = tabs.findIndex(t => t.id === currentTab);
            const next = tabs[idx + 1];
            if (next) dispatch({ type: 'SET_CURRENT_TAB', tab: next.id });
        },
        () => { // swipe right → prev tab
            const idx = tabs.findIndex(t => t.id === currentTab);
            const prev = tabs[idx - 1];
            if (prev) dispatch({ type: 'SET_CURRENT_TAB', tab: prev.id });
        },
    );

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

    const tabs = useMemo(() => {
        if (currentStory) {
            if (isChatOnly) return CHAT_STORY_TABS;
            if (isMobile) return [...STORY_TABS, { ...CHAT_TAB, right: true }];
            return STORY_TABS;
        }
        if (currentWorld) return isChatOnly ? CHAT_WORLD_TABS : WORLD_TABS;
        return [{ id: "menu" as Tab, label: "Menu", icon: List }];
    }, [currentStory, currentWorld, isChatOnly, isMobile]);

    // 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}>{Prompt.substituteVars(appState, currentWorld!.title)}</span>
            <span class={styles.titleSep}>/</span>{Prompt.substituteVars(appState, currentStory.title)}</div>
        : currentWorld
            ? <div class={styles.title}><WorldIcon size={24} />{Prompt.substituteVars(appState, currentWorld.title)}</div>
            : null;

    return (
        <div class={styles.editor} ref={editorRef}>
            {currentTab !== 'menu' && titleBar}
            <div class={clsx(
                styles.content,
                currentTab === 'menu' && styles.menuContent,
                currentTab === 'chat' && styles.chatContent,
            )} ref={contentRef}>
                <Menu visible={currentTab === "menu"} />
                {currentStory && (<>
                    <StoryEditor visible={currentTab === "story"} />
                    <ChaptersEditor visible={currentTab === "chapters"} />
                    <ScratchpadEditor visible={currentTab === "scratchpad"} />
                    <div
                        class={clsx(styles.promptPreview, currentTab !== "prompt" && styles.tabHidden)}
                        dangerouslySetInnerHTML={{ __html: promptPreview }}
                    />
                    {(isChatOnly || isMobile) && <ChatPanel visible={currentTab === "chat"} />}
                </>)}
                {(currentStory || currentWorld) && (<>
                    <LoreEditor visible={currentTab === "lore"} />
                    <CharacterEditor visible={currentTab === "characters"} />
                    <LocationEditor visible={currentTab === "locations"} />
                </>)}
                {currentWorld && <SystemEditor visible={currentTab === "system"} />}
            </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 && !isMobile && (
                    <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>
    );
};
