import React, {ChangeEvent, useContext, useEffect, useRef, useState} from 'react';
import {
    BarChart2,
    BookMarked,
    BookOpen,
    ChevronRight,
    Clock,
    CloudSun,
    FileText,
    GraduationCap,
    Languages,
    Loader2,
    LucideIcon,
    MessageSquare,
    Music,
    Pencil,
    RotateCw,
    Square,
    User,
    UserPen,
    Wand2,
    X
} from 'lucide-react';
import {writingLevel} from "@/lib/constants/user";
import {
    advancedDialogueTypes,
    advancedNarrativePersons,
    advancedPredefinedType,
    beginnerDialogueTypes,
    beginnerNarrativePersons,
    beginnerPredefinedType,
    intermediateDialogueTypes,
    intermediateNarrativePersons,
    intermediatePredefinedType,
    langues,
    verbalTime
} from '@/lib/constants/story';
import {presetStoryType} from '@/lib/utils/story';
import SelectBox from "@/components/form/SelectBox";
import TextInput from "@/components/form/TextInput";
import TextAreaInput from "@/components/form/TextAreaInput";
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
import {apiPost} from '@/lib/api/client';
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import {configs} from "@/lib/configs";
import InputField from "@/components/form/InputField";
import NumberInput from "@/components/form/NumberInput";
import Button from "@/components/ui/Button";
import IconButton from "@/components/ui/IconButton";
import PulseLoader from "@/components/ui/PulseLoader";
import {Editor as TipEditor, EditorContent, useEditor} from "@tiptap/react";
import {convertToHtml} from "@/lib/utils/editor";
import StarterKit from "@tiptap/starter-kit";
import Underline from "@tiptap/extension-underline";
import TextAlign from "@tiptap/extension-text-align";
import {getSubLevel, isAnthropicEnabled} from "@/lib/utils/quillsense";
import {useTranslations} from '@/lib/i18n';
import {LangContext, LangContextProps} from "@/context/LangContext";
import {AIUsageContext, AIUsageContextProps} from "@/context/AIUsageContext";
import AdvancedGenerationOptions from "@/components/form/AdvancedGenerationOptions";

interface ShortStoryGeneratorProps {
    onClose: () => void;
}

interface TabItem {
    id: number;
    label: string;
    icon: LucideIcon;
}

export default function ShortStoryGenerator({onClose}: ShortStoryGeneratorProps) {
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {errorMessage, infoMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext)
    const t = useTranslations();
    const {setTotalPrice, setTotalCredits}: AIUsageContextProps = useContext<AIUsageContextProps>(AIUsageContext)
    
    const [tone, setTone] = useState<string>('');
    const [atmosphere, setAtmosphere] = useState<string>('');
    const [verbTense, setVerbTense] = useState<string>('0');
    const [person, setPerson] = useState<string>('0');
    const [characters, setCharacters] = useState<string>('');
    const [language, setLanguage] = useState<string>(session.user?.writingLang?.toString() ?? '0');
    const [dialogueType, setDialogueType] = useState<string>('0');
    const [wordsCount, setWordsCount] = useState<number>(500)
    const [directives, setDirectives] = useState<string>('');
    const [authorLevel, setAuthorLevel] = useState<string>(session.user?.writingLevel?.toString() ?? '0');
    const [presetType, setPresetType] = useState<string>('0');

    const [activeTab, setActiveTab] = useState<number>(1);
    const [progress, setProgress] = useState<number>(25);
    const [isGenerating, setIsGenerating] = useState<boolean>(false);
    const progressRef = useRef<HTMLDivElement>(null);

    const [generatedText, setGeneratedText] = useState<string>('');
    const [generatedStoryTitle, setGeneratedStoryTitle] = useState<string>('');
    const [resume, setResume] = useState<string>('');
    const [totalWordsCount, setTotalWordsCount] = useState<number>(0);

    const [hasGenerated, setHasGenerated] = useState<boolean>(false);
    const [abortController, setAbortController] = useState<ReadableStreamDefaultReader<Uint8Array> | null>(null);
    
    const [useExplicit, setUseExplicit] = useState<boolean>(false);
    const [useSmart, setUseSmart] = useState<boolean>(false);
    
    useEffect((): void => {
        if (progressRef.current) {
            progressRef.current.style.width = `${progress}%`;
        }
    }, [progress]);

    const anthropicEnabled: boolean = isAnthropicEnabled(session);
    const isSubTierTwo: boolean = getSubLevel(session) >= 2;
    const hasAccess: boolean = anthropicEnabled || isSubTierTwo;

    const editor: TipEditor | null = useEditor({
        extensions: [
            StarterKit,
            Underline,
            TextAlign.configure({
                types: ['heading', 'paragraph'],
            }),
        ],
        injectCSS: false,
        immediatelyRender: false,
    });
    
    useEffect((): () => void => {
        document.body.style.overflow = 'hidden';
        return (): void => {
            document.body.style.overflow = 'auto';
        };
    }, []);
    
    useEffect((): void => {
        presetStoryType(
            presetType,
            setTone,
            setAtmosphere,
            setVerbTense,
            setPerson,
            setDialogueType,
            (): void => {
            },
        );
    }, [presetType]);
    
    useEffect((): void => {
        setProgress(activeTab * 25);
    }, [activeTab]);
    
    useEffect((): void => {
        if (editor)
            editor.commands.setContent(convertToHtml(generatedText))
        getWordCount();
    }, [editor, generatedText]);
    
    async function handleStopGeneration(): Promise<void> {
        if (abortController) {
            await abortController.cancel();
            setAbortController(null);
            infoMessage(t("shortStoryGenerator.result.abortSuccess"));
        }
    }

    async function handleGeneration(): Promise<void> {
        setIsGenerating(true);
        setGeneratedText('');
        
        try {
            const response: Response = await fetch(`${configs.apiUrl}quillsense/generate/short`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${session.accessToken}`,
                },
                body: JSON.stringify({
                    authorLevel: authorLevel,
                    tone: tone,
                    atmosphere: atmosphere,
                    verbTense: verbTense,
                    person: person,
                    characters: characters,
                    language: language,
                    dialogueType: dialogueType,
                    directives: directives,
                    wordsCount: wordsCount,
                    useExplicit: useExplicit,
                    useSmart: useSmart,
                }),
            });
            
            if (!response.ok) {
                const error: { message?: string } = await response.json();
                errorMessage(error.message || t("shortStoryGenerator.result.unknownError"));
                setIsGenerating(false);
                return;
            }
            setActiveTab(4);
            setProgress(100);
            
            const reader: ReadableStreamDefaultReader<Uint8Array> | undefined = response.body?.getReader();
            const decoder: TextDecoder = new TextDecoder();
            let accumulatedText: string = '';
            
            if (!reader) {
                errorMessage(t("shortStoryGenerator.result.noResponse"));
                setIsGenerating(false);
                return;
            }
            
            setAbortController(reader);
            
            while (true) {
                try {
                    const {done, value}: ReadableStreamReadResult<Uint8Array> = await reader.read();
                    
                    if (done) break;
                    
                    const chunk: string = decoder.decode(value, {stream: true});
                    const lines: string[] = chunk.split('\n');
                    
                    for (const line of lines) {
                        if (line.startsWith('data: ')) {
                            try {
                                const data: {
                                    content?: string;
                                    title?: string;
                                    useYourKey?: boolean;
                                    totalPrice?: number;
                                    totalCost?: number;
                                } = JSON.parse(line.slice(6));

                                if (data.content && data.content !== 'starting') {
                                    accumulatedText += data.content;
                                    setGeneratedText(accumulatedText);
                                }
                                
                                // Le message final du endpoint avec title, totalPrice, useYourKey, totalCost
                                if (data.title && data.useYourKey !== undefined && data.totalPrice !== undefined) {
                                    setGeneratedStoryTitle(data.title);
                                    if (data.useYourKey) {
                                        setTotalPrice((prev: number): number => prev + data.totalPrice!);
                                    } else {
                                        setTotalCredits(data.totalPrice);
                                    }
                                }
                            } catch (e: unknown) {
                                errorMessage(t("shortStoryGenerator.result.parsingError"));
                            }
                        }
                    }
                } catch (e: unknown) {
                    break;
                }
            }

            setIsGenerating(false);
            setHasGenerated(true);
            setAbortController(null);
        } catch (e: unknown) {
            if (e instanceof Error) {
                if (e.name !== 'AbortError') {
                    errorMessage(e.message);
                }
            } else {
                errorMessage(t("shortStoryGenerator.result.unknownError"));
            }
            setIsGenerating(false);
            setAbortController(null);
        }
    }

    function getWordCount(): void {
        if (editor) {
            try {
                const content: string = editor?.state.doc.textContent;
                const texteNormalise: string = content
                    .replace(/'/g, ' ')
                    .replace(/-/g, ' ')
                    .replace(/\s+/g, ' ')
                    .trim();
                const mots: string[] = texteNormalise.split(' ');
                const wordCount: number = mots.filter(
                    (mot: string): boolean => mot.length > 0,
                ).length;
                setTotalWordsCount(wordCount);
            } catch (e: unknown) {
                if (e instanceof Error) {
                    errorMessage(e.message);
                } else {
                    errorMessage(t("shortStoryGenerator.result.unknownError"));
                }
            }
        }
    }

    async function handleSave(): Promise<void> {
        let content: Record<string, unknown> | string = '';
        if (editor) content = editor.state.doc.toJSON();
        try {
            const bookId: string = await apiPost<string>(
                `quillsense/generate/add`,
                {
                    title: generatedStoryTitle,
                    resume: resume,
                    content: content,
                    wordCount: totalWordsCount,
                    tone: tone,
                    atmosphere: atmosphere,
                    verbTense: verbTense,
                    language: language,
                    dialogueType: dialogueType,
                    person: person,
                    authorLevel: authorLevel
                        ? authorLevel
                        : session.user?.writingLevel,
                },
                session.accessToken,
                lang
            );
            if (!bookId) {
                errorMessage(t("shortStoryGenerator.result.saveError"));
                return;
            }
            onClose();
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("shortStoryGenerator.result.unknownError"));
            }
        }
    }

    if (!hasAccess) {
        return (
            <div
                className="fixed inset-0 flex items-center justify-center p-4 bg-darkest-background/60 z-50 backdrop-blur-md animate-fadeIn">
                <div
                    className="relative bg-tertiary text-text-primary rounded-xl overflow-hidden w-full max-w-md p-6">
                    <h2 className="flex items-center font-['ADLaM_Display'] text-xl text-text-primary mb-4">
                        <Wand2 className="mr-3 w-5 h-5" strokeWidth={1.75}/>
                        {t("shortStoryGenerator.accessDenied.title")}
                    </h2>
                    <p className="text-text-secondary mb-6">
                        {t("shortStoryGenerator.accessDenied.message")}
                    </p>
                    <Button variant="primary" onClick={onClose} fullWidth>
                        {t("shortStoryGenerator.accessDenied.close")}
                    </Button>
                </div>
            </div>
        );
    }

    return (
        <div
            className="fixed inset-0 flex items-center justify-center p-4 bg-darkest-background/60 z-40 backdrop-blur-md animate-fadeIn">
            <div
                className="relative bg-tertiary text-text-primary rounded-xl max-h-[90vh] overflow-hidden flex flex-col w-full max-w-4xl">
                
                <div className="flex justify-between items-center px-6 py-4">
                    <h2 className="font-['ADLaM_Display'] text-xl text-text-primary flex items-center">
                        <Wand2 className="mr-3 w-5 h-5" strokeWidth={1.75}/>
                        {t("shortStoryGenerator.title")}
                    </h2>
                    <IconButton icon={X} variant="light" onClick={onClose} disabled={isGenerating}/>
                </div>
                
                <div className="flex-1 min-h-0 bg-darkest-background rounded-xl mx-2 flex flex-col overflow-hidden">
                    <div className="px-4 pt-4 pb-2">
                        <div className="w-full bg-secondary rounded-full h-2">
                            <div
                                ref={progressRef}
                                className="bg-primary h-2 rounded-full transition-all duration-300"
                            />
                        </div>
                    </div>

                    <div className="flex border-b border-secondary">
                        {([
                            {id: 1, label: t("shortStoryGenerator.tabs.basics"), icon: BookOpen},
                            {id: 2, label: t("shortStoryGenerator.tabs.structure"), icon: UserPen},
                            {id: 3, label: t("shortStoryGenerator.tabs.atmosphere"), icon: CloudSun},
                            ...(hasGenerated || isGenerating ? [{
                                id: 4,
                                label: t("shortStoryGenerator.tabs.result"),
                                icon: FileText
                            }] : [])
                        ] satisfies TabItem[]).map((tab: TabItem): React.JSX.Element => {
                            const TabIcon: LucideIcon = tab.icon;
                            return (
                                <button
                                    key={tab.id}
                                    onClick={(): void => setActiveTab(tab.id)}
                                    disabled={isGenerating}
                                    className={`flex items-center px-6 py-3 font-medium transition-colors ${
                                        activeTab === tab.id
                                            ? 'text-primary border-b-2 border-primary bg-primary/5'
                                            : 'text-text-secondary hover:text-text-primary'
                                    }`}
                                >
                                    <TabIcon className="mr-2 w-4 h-4" strokeWidth={1.75}/>
                                    {tab.label}
                                    {tab.id === 4 && isGenerating && !generatedText && (
                                        <Loader2 className="ml-2 animate-spin w-4 h-4" strokeWidth={1.75}/>
                                    )}
                                </button>
                            );
                        })}
                    </div>
                    
                    <div className="flex-1 min-h-0 overflow-auto custom-scrollbar">
                    {activeTab === 1 && (
                        <div className="p-5 space-y-6">
                            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                                <InputField
                                    icon={GraduationCap}
                                    fieldName={t("shortStoryGenerator.fields.complexity")}
                                    input={
                                        <SelectBox
                                            onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => setAuthorLevel(e.target.value)}
                                            data={writingLevel}
                                            defaultValue={authorLevel}
                                        />
                                    }
                                />
                                <InputField
                                    icon={BookOpen}
                                    fieldName={t("shortStoryGenerator.fields.preset")}
                                    input={
                                        <SelectBox
                                            onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => setPresetType(e.target.value)}
                                            data={
                                                authorLevel === '1'
                                                    ? beginnerPredefinedType
                                                    : authorLevel === '2'
                                                        ? intermediatePredefinedType
                                                        : advancedPredefinedType
                                            }
                                            defaultValue={presetType}
                                        />
                                    }
                                />
                                <InputField
                                    icon={Languages}
                                    fieldName={t("shortStoryGenerator.fields.language")}
                                    input={
                                        <SelectBox
                                            onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => setLanguage(e.target.value)}
                                            data={langues}
                                            defaultValue={language}
                                        />
                                    }
                                />
                                <InputField
                                    icon={BarChart2}
                                    fieldName={t("shortStoryGenerator.fields.wordCount")}
                                    input={
                                        <NumberInput
                                            value={wordsCount}
                                            setValue={setWordsCount}
                                            placeholder="500"
                                        />
                                    }
                                />
                            </div>
                        </div>
                    )}

                    {activeTab === 2 && (
                        <div className="p-5 space-y-6">
                            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                                <InputField
                                    icon={Clock}
                                    fieldName={t("shortStoryGenerator.fields.tense")}
                                    input={
                                        <SelectBox
                                            onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => setVerbTense(e.target.value)}
                                            data={verbalTime}
                                            defaultValue={verbTense}
                                        />
                                    }
                                />
                                <InputField
                                    icon={UserPen}
                                    fieldName={t("shortStoryGenerator.fields.narrative")}
                                    input={
                                        <SelectBox
                                            onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => setPerson(e.target.value)}
                                            data={
                                                authorLevel === '1'
                                                    ? beginnerNarrativePersons
                                                    : authorLevel === '2'
                                                        ? intermediateNarrativePersons
                                                        : advancedNarrativePersons
                                            }
                                            defaultValue={person}
                                        />
                                    }
                                />
                            </div>

                            <InputField
                                icon={MessageSquare}
                                fieldName={t("shortStoryGenerator.fields.dialogue")}
                                input={
                                    <SelectBox
                                        onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => setDialogueType(e.target.value)}
                                        data={
                                            authorLevel === '1'
                                                ? beginnerDialogueTypes
                                                : authorLevel === '2'
                                                    ? intermediateDialogueTypes
                                                    : advancedDialogueTypes
                                        }
                                        defaultValue={dialogueType}
                                    />
                                }
                            />

                            <InputField
                                icon={Pencil}
                                fieldName={t("shortStoryGenerator.fields.directives")}
                                input={
                                    <TextAreaInput
                                        value={directives}
                                        setValue={(e: ChangeEvent<HTMLTextAreaElement>) => setDirectives(e.target.value)}
                                        placeholder={t("shortStoryGenerator.placeholders.directives")}
                                    />
                                }
                            />
                        </div>
                    )}

                    {activeTab === 3 && (
                        <div className="p-5 space-y-6">
                            <InputField
                                icon={Music}
                                fieldName={t("shortStoryGenerator.fields.tone")}
                                input={
                                    <TextInput
                                        value={tone}
                                        setValue={(e: ChangeEvent<HTMLInputElement>) => setTone(e.target.value)}
                                        placeholder={t("shortStoryGenerator.placeholders.tone")}
                                    />
                                }
                            />
                            
                            <InputField
                                icon={CloudSun}
                                fieldName={t("shortStoryGenerator.fields.atmosphere")}
                                input={
                                    <TextInput
                                        value={atmosphere}
                                        setValue={(e: ChangeEvent<HTMLInputElement>) => setAtmosphere(e.target.value)}
                                        placeholder={t("shortStoryGenerator.placeholders.atmosphere")}
                                    />
                                }
                            />

                            <InputField
                                icon={User}
                                fieldName={t("shortStoryGenerator.fields.character")}
                                input={
                                    <TextInput
                                        value={characters}
                                        setValue={(e: ChangeEvent<HTMLInputElement>) => setCharacters(e.target.value)}
                                        placeholder={t("shortStoryGenerator.placeholders.character")}
                                    />
                                }
                            />
                            
                            <AdvancedGenerationOptions
                                useExplicit={useExplicit}
                                setUseExplicit={setUseExplicit}
                                useSmart={useSmart}
                                setUseSmart={setUseSmart}
                            />
                        </div>
                    )}

                    {activeTab === 4 && (
                        <div className="p-5">
                            <div className="flex justify-between items-center mb-4">
                                <h3 className="font-semibold text-lg">
                                    {generatedStoryTitle || t("shortStoryGenerator.result.title")}
                                </h3>

                                <div className="flex items-center space-x-2">
                                    {isGenerating ? (
                                        <IconButton icon={Square} variant="danger" onClick={handleStopGeneration}
                                                    tooltip={t("shortStoryGenerator.actions.stop")}/>
                                    ) : generatedText && (
                                        <>
                                            <IconButton icon={RotateCw} variant="muted" onClick={handleGeneration}
                                                        tooltip={t("shortStoryGenerator.actions.regenerate")}/>
                                            <IconButton icon={BookMarked} variant="primary" onClick={handleSave}
                                                        tooltip={t("shortStoryGenerator.actions.save")}/>
                                        </>
                                    )}
                                </div>
                            </div>

                            {isGenerating && !generatedText ? (
                                <PulseLoader text={t("shortStoryGenerator.result.generating")} size="lg"/>
                            ) : (
                                <div
                                    className="rounded-lg p-6 overflow-auto max-h-96 fade-in-text">
                                    <EditorContent editor={editor} className="prose prose-invert max-w-none"/>
                                </div>
                            )}

                            {generatedText && (
                                <div className="flex justify-between items-center mt-4 pt-4 border-t border-secondary">
                                    <div className="flex items-center text-sm text-text-secondary">
                                        <BarChart2 className="mr-2 w-4 h-4" strokeWidth={1.75}/>
                                        {totalWordsCount} {t("shortStoryGenerator.result.words")}
                                    </div>
                                </div>
                            )}
                        </div>
                    )}
                    </div>
                </div>
                
                <div className="flex justify-between items-center px-6 py-4">
                    <Button variant="ghost" onClick={(): void => setActiveTab(Math.max(1, activeTab - 1))}
                            disabled={activeTab === 1 || isGenerating}>
                        <ChevronRight className="rotate-180 w-4 h-4" strokeWidth={1.75}/>
                        {t("shortStoryGenerator.navigation.previous")}
                    </Button>

                    <div className="flex items-center space-x-3">
                        <Button variant="secondary" onClick={onClose} disabled={isGenerating}>
                            {activeTab === 4 && hasGenerated ? t("shortStoryGenerator.navigation.close") : t("shortStoryGenerator.navigation.cancel")}
                        </Button>

                        {activeTab < 3 ? (
                            <Button variant="primary" onClick={(): void => setActiveTab(activeTab + 1)}
                                    disabled={isGenerating}>
                                {t("shortStoryGenerator.navigation.next")}
                                <ChevronRight className="w-4 h-4" strokeWidth={1.75}/>
                            </Button>
                        ) : activeTab === 3 && (
                            <Button variant="primary" icon={Wand2} onClick={handleGeneration}
                                    disabled={isGenerating} isLoading={isGenerating}
                                    loadingText={t("shortStoryGenerator.actions.generating")}>
                                {t("shortStoryGenerator.actions.generate")}
                            </Button>
                        )}
                    </div>
                </div>
            </div>
        </div>
    );
}