import React, {ChangeEvent, useContext, useState} from 'react';
import {BookOpen, FileInput, Hash, Palette, Wand2} from 'lucide-react';
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import {EditorContext, EditorContextProps} from "@/context/EditorContext";
import {apiGet} from "@/lib/api/client";
import {htmlToText, textContentToHtml} from "@/lib/utils/html";
import {BookContext, BookContextProps} from "@/context/BookContext";
import {ChapterContext, ChapterContextProps} from "@/context/ChapterContext";
import QSTextGeneratedPreview from "@/components/ui/QSTextGeneratedPreview";
import TextInput from "@/components/form/TextInput";
import InputField from "@/components/form/InputField";
import RadioBox from "@/components/form/RadioBox";
import TextAreaInput from "@/components/form/TextAreaInput";
import Button from "@/components/ui/Button";
import NumberInput from "@/components/form/NumberInput";
import SectionHeader from "@/components/ui/SectionHeader";
import GhostWriterTags from "@/components/ghostwriter/GhostWriterTags";
import {TiptapNode} from "@/lib/types/chapter";
import {convertTiptapToHTML} from "@/lib/utils/tiptap";
import {useTranslations} from '@/lib/i18n';
import {getSubLevel, isOpenAIEnabled} from "@/lib/utils/quillsense";
import {AIUsageContext, AIUsageContextProps} from "@/context/AIUsageContext";
import {LangContext, LangContextProps} from "@/context/LangContext";
import {configs} from "@/lib/configs";
import AdvancedGenerationOptions from "@/components/form/AdvancedGenerationOptions";

export default function GhostWriter() {
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {errorMessage, infoMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {editor}: EditorContextProps = useContext<EditorContextProps>(EditorContext);
    const {book}: BookContextProps = useContext<BookContextProps>(BookContext);
    const {chapter}: ChapterContextProps = useContext<ChapterContextProps>(ChapterContext);
    const {setTotalPrice, setTotalCredits}: AIUsageContextProps = useContext<AIUsageContextProps>(AIUsageContext);

    const [minWords, setMinWords] = useState<number>(500);
    const [maxWords, setMaxWords] = useState<number>(1000);
    const [toneAtmosphere, setToneAtmosphere] = useState<string>('');
    const [directive, setDirective] = useState<string>('');
    const [type, setType] = useState<number>(0);
    const [isGenerating, setIsGenerating] = useState<boolean>(false);
    const [textGenerated, setTextGenerated] = useState<string>('');
    const [isTextGenerated, setIsTextGenerated] = useState<boolean>(false);
    const [taguedCharacters, setTaguedCharacters] = useState<string[]>([]);
    const [taguedLocations, setTaguedLocations] = useState<string[]>([]);
    const [taguedObjects, setTaguedObjects] = useState<string[]>([]);
    const [taguedWorldElements, setTaguedWorldElements] = useState<string[]>([]);
    const [abortController, setAbortController] = useState<ReadableStreamDefaultReader<Uint8Array> | null>(null);

    const [useExplicit, setUseExplicit] = useState<boolean>(false);
    const [useSmart, setUseSmart] = useState<boolean>(false);
    
    const isGPTEnabled: boolean = isOpenAIEnabled(session);
    const isSubTierTree: boolean = getSubLevel(session) === 3;
    const hasAccess: boolean = isGPTEnabled || isSubTierTree;

    async function handleStopGeneration(): Promise<void> {
        if (abortController) {
            await abortController.cancel();
            setAbortController(null);
            infoMessage(t("ghostWriter.abortSuccess"));
        }
    }

    async function handleGenerateGhostWriter(): Promise<void> {
        setIsGenerating(true);
        setIsTextGenerated(false);
        setTextGenerated('');
        
        try {
            let content: string = '';
            if (editor?.getText()) {
                try {
                    content = editor?.getText();
                } catch (e: unknown) {
                    if (e instanceof Error) {
                        errorMessage(t('ghostWriter.errorRetrieveContent'));
                    } else {
                        errorMessage(t('ghostWriter.errorUnknownRetrieveContent'));
                    }
                }
            }
            
            const response: Response = await fetch(`${configs.apiUrl}quillsense/ghostwriter/generate`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${session.accessToken}`,
                },
                body: JSON.stringify({
                    bookId: book?.bookId,
                    minWords: minWords,
                    maxWords: maxWords,
                    toneAtmosphere: toneAtmosphere,
                    directive: directive,
                    positionType: type,
                    content: content,
                    tags: {
                        characters: taguedCharacters,
                        locations: taguedLocations,
                        objects: taguedObjects,
                        worldElements: taguedWorldElements,
                    },
                    useExplicit: useExplicit,
                    useSmart: useSmart,
                }),
            });
            
            if (!response.ok) {
                const error: { message?: string } = await response.json();
                errorMessage(error.message || t('ghostWriter.errorGenerate'));
                setIsGenerating(false);
                return;
            }
            
            const reader: ReadableStreamDefaultReader<Uint8Array> | undefined = response.body?.getReader();
            const decoder: TextDecoder = new TextDecoder();
            let accumulatedText: string = '';
            
            if (!reader) {
                errorMessage(t('ghostWriter.errorGenerate'));
                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 dataStr: string = line.slice(6);
                                const data: {
                                    content?: string;
                                    totalCost?: number;
                                    totalPrice?: number;
                                    useYourKey?: boolean;
                                } = JSON.parse(dataStr);
                                if ('content' in data && data.content) {
                                    accumulatedText += data.content;
                                    setTextGenerated(accumulatedText);
                                }
                                else if ('useYourKey' in data && 'totalPrice' in data) {
                                    if (data.useYourKey) {
                                        setTotalPrice((prev: number): number => prev + data.totalPrice!);
                                    } else {
                                        setTotalCredits(data.totalPrice!);
                                    }
                                }
                            } catch (e: unknown) {
                                errorMessage(t('ghostWriter.errorProcessingData'));
                            }
                        }
                    }
                } catch (e: unknown) {
                    break;
                }
            }

            setIsGenerating(false);
            setIsTextGenerated(true);
            setAbortController(null);
        } catch (e: unknown) {
            setIsGenerating(false);
            setAbortController(null);
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('ghostWriter.errorUnknown'));
            }
        }
    }
    
    async function importPrompt(): Promise<void> {
        try {
            const response: TiptapNode = await apiGet<TiptapNode>(
                `chapter/content`,
                session.accessToken,
                lang,
                {
                    chapterid: chapter?.chapterId,
                    version: 1
                },
            )
            if (!response) {
                errorMessage(t('ghostWriter.noContentFound'));
                return;
            }
            const content: string = htmlToText(convertTiptapToHTML(response));
            setDirective(content);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('ghostWriter.errorUnknownImport'));
            }
        }
    }
    
    function insertText(): void {
        if (editor && textGenerated) {
            editor.commands.focus('end');
            if (editor.getText().length > 0) {
                editor.commands.insertContent('\n\n');
            }
            editor.commands.insertContent(textContentToHtml(textGenerated));
            setIsTextGenerated(false);
        }
    }
    
    if (!hasAccess) {
        return (
            <div className="flex items-center justify-center h-full">
                <div className="bg-tertiary rounded-2xl p-10 text-center max-w-md">
                    <h2 className="text-2xl font-['ADLaM_Display'] text-text-primary mb-4">{t("ghostWriter.title")}</h2>
                    <p className="text-muted mb-6 text-lg leading-relaxed">{t("ghostWriter.subscriptionRequired")}</p>
                    <Button
                        variant="primary"
                        size="lg"
                        onClick={(): void => {
                            window.location.href = '/pricing';
                        }}
                    >
                        {t("ghostWriter.subscribe")}
                    </Button>
                </div>
            </div>
        );
    }
    
    return (
        <div className="flex flex-col h-full overflow-hidden">
            <SectionHeader
                title={t("ghostWriter.title")}
                description={t("ghostWriter.description")}
                badge="AI"
            />
            
            <div className="p-4 lg:p-5 space-y-6 overflow-y-auto flex-grow custom-scrollbar">
                <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <InputField
                        icon={Hash}
                        fieldName={t("ghostWriter.minimum")}
                        input={
                            <NumberInput
                                value={minWords}
                                setValue={setMinWords}
                                placeholder={t("ghostWriter.words")}
                            />
                        }
                    />
                    <InputField
                        icon={Hash}
                        fieldName={t("ghostWriter.maximum")}
                        input={
                            <NumberInput
                                value={maxWords}
                                setValue={setMaxWords}
                                placeholder={t("ghostWriter.words")}
                            />
                        }
                    />
                </div>
                
                <InputField
                    icon={BookOpen}
                    fieldName={t("ghostWriter.type")}
                    input={<RadioBox selected={type} setSelected={setType} name={'sectionType'}/>}
                />
                
                <InputField
                    icon={Palette}
                    fieldName={t("ghostWriter.toneAtmosphere")}
                    input={
                        <TextInput
                            value={toneAtmosphere}
                            setValue={(e: ChangeEvent<HTMLInputElement>) => setToneAtmosphere(e.target.value)}
                            placeholder={t("ghostWriter.tonePlaceholder")}
                        />
                    }
                />
                
                <InputField
                    icon={Wand2}
                    fieldName={t("ghostWriter.directive")}
                    action={importPrompt}
                    actionIcon={FileInput}
                    actionLabel={t("ghostWriter.importPrompt")}
                    input={
                        <TextAreaInput
                            value={directive}
                            setValue={(e: ChangeEvent<HTMLTextAreaElement>) => setDirective(e.target.value)}
                            placeholder={t("ghostWriter.directivePlaceholder")}
                        />
                    }
                />
                
                <GhostWriterTags
                    taguedCharacters={taguedCharacters} setTaguedCharacters={setTaguedCharacters}
                    taguedLocations={taguedLocations} setTaguedLocations={setTaguedLocations}
                    taguedObjects={taguedObjects} setTaguedObjects={setTaguedObjects}
                    taguedWorldElements={taguedWorldElements} setTaguedWorldElements={setTaguedWorldElements}
                />
                
                <AdvancedGenerationOptions
                    useExplicit={useExplicit}
                    setUseExplicit={setUseExplicit}
                    useSmart={useSmart}
                    setUseSmart={setUseSmart}
                />
            </div>

            <div className="p-5 shrink-0">
                <div className="flex justify-center">
                    <Button
                        variant="primary"
                        onClick={handleGenerateGhostWriter}
                        isLoading={isGenerating}
                        loadingText={t("ghostWriter.generating")}
                        icon={Wand2}
                    >{t("ghostWriter.generate")}</Button>
                </div>
            </div>
            {(isTextGenerated || isGenerating) && (
                <QSTextGeneratedPreview
                    onClose={(): void => setIsTextGenerated(false)}
                    onRefresh={(): Promise<void> => handleGenerateGhostWriter()}
                    value={textGenerated}
                    onInsert={insertText}
                    isGenerating={isGenerating}
                    onStop={handleStopGeneration}
                />
            )}
        </div>
    );
}
