import {ChangeEvent, useContext, useState} from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {
    faBookOpen,
    faFileImport,
    faFloppyDisk,
    faGear,
    faGhost,
    faHashtag,
    faMagicWandSparkles,
    faPalette,
    faTags,
    faX
} from '@fortawesome/free-solid-svg-icons';
import {SessionContext} from "@/context/SessionContext";
import {AlertContext} from "@/context/AlertContext";
import {EditorContext} from "@/context/EditorContext";
import System from "@/lib/models/System";
import {BookContext} from "@/context/BookContext";
import {ChapterContext} from "@/context/ChapterContext";
import QSTextGeneratedPreview from "@/components/QSTextGeneratedPreview";
import TextInput from "@/components/form/TextInput";
import InputField from "@/components/form/InputField";
import RadioBox from "@/components/form/RadioBox";
import TexteAreaInput from "@/components/form/TexteAreaInput";
import SubmitButtonWLoading from "@/components/form/SubmitButtonWLoading";
import NumberInput from "@/components/form/NumberInput";
import PanelHeader from "@/components/PanelHeader";
import GhostWriterTags from "@/components/ghostwriter/GhostWriterTags";
import Chapter, {TiptapNode} from "@/lib/models/Chapter";
import GhostWriterSettings from "@/components/ghostwriter/GhostWriterSettings";
import {useTranslations} from "next-intl";
import QuillSense, {AIGeneratedText} from "@/lib/models/QuillSense";
import {AIUsageContext, AIUsageContextProps} from "@/context/AIUsageContext";
import {LangContext} from "@/context/LangContext";
import {configs} from "@/lib/configs";

export default function GhostWriter() {
    const t = useTranslations();
    const {lang} = useContext(LangContext)
    const {session} = useContext(SessionContext);
    const {errorMessage, successMessage, infoMessage} = useContext(AlertContext);
    const {editor} = useContext(EditorContext);
    const {book} = useContext(BookContext);
    const {chapter} = useContext(ChapterContext);
    const {setTotalPrice, setTotalCredits} = 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 [advanceSettings, setAdvanceSettings] = useState<boolean>(false);
    const [advancedPrompt, setAdvancedPrompt] = useState<string>('');
    const [showTags, setShowTags] = 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 isGPTEnabled: boolean = QuillSense.isOpenAIEnabled(session);
    const isSubTierTree: boolean = QuillSense.getSubLevel(session) === 3;
    const hasAccess: boolean = isGPTEnabled || isSubTierTree;
    
    async function showAdvanceSetting(): Promise<void> {
        if (advanceSettings) {
            await handleSaveAdvancedSettings();
            setAdvanceSettings(false);
        } else {
            setAdvanceSettings(true);
        }
    }
    
    async function handleSaveAdvancedSettings(): Promise<void> {
        try {
            if (advancedPrompt.trim() === '') {
                errorMessage(t('ghostWriter.promptEmpty'));
                return;
            }
            const response: boolean = await System.authPostToServer<boolean>(`quillsense/ghostwriter/advanced-settings`, {
                bookId: book?.bookId,
                advancedPrompt: advancedPrompt
            }, session.accessToken, lang);
            if (!response) {
                errorMessage(t('ghostWriter.errorSaveAdvanced'));
                return;
            }
            successMessage(t('ghostWriter.successSaveAdvanced'));
            setAdvanceSettings(false);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(t('ghostWriter.errorSave'));
            } else {
                errorMessage(t('ghostWriter.errorUnknown'));
            }
        }
    }
    
    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,
                    },
                }),
            });
            
            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 System.authGetQueryToServer<TiptapNode>(
                `chapter/content`,
                session.accessToken,
                lang,
                {
                    chapterid: chapter?.chapterId,
                    version: 1
                },
            )
            if (!response) {
                errorMessage(t('ghostWriter.noContentFound'));
                return;
            }
            const content: string = System.htmlToText(Chapter.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(System.textContentToHtml(textGenerated));
            setIsTextGenerated(false);
        }
    }
    
    if (!hasAccess || !book?.quillsenseEnabled) {
        return (
            <div className="flex items-center justify-center h-full">
                <div
                    className="bg-tertiary/90 backdrop-blur-sm p-10 rounded-2xl shadow-2xl text-center border border-secondary/50 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">
                        {!book?.quillsenseEnabled
                            ? t("ghostWriter.quillsenseDisabled")
                            : t("ghostWriter.subscriptionRequired")}
                    </p>
                    {hasAccess && !book?.quillsenseEnabled ? null : (
                        <button
                            onClick={(): string => window.location.href = '/pricing'}
                            className="px-6 py-3 bg-primary text-text-primary rounded-xl hover:bg-primary-dark transition-all duration-200 hover:scale-105 shadow-md hover:shadow-lg font-semibold"
                        >
                            {t("ghostWriter.subscribe")}
                        </button>
                    )}
                </div>
            </div>
        );
    }
    
    return (
        <div className="bg-secondary/20 backdrop-blur-sm flex flex-col h-full overflow-hidden">
            <PanelHeader
                title={t("ghostWriter.title")}
                description={t("ghostWriter.description")}
                badge="AI"
                icon={faGhost}
            />
            
            {
                showTags ? (
                    <GhostWriterTags taguedCharacters={taguedCharacters} setTaguedCharacters={setTaguedCharacters}
                                     taguedLocations={taguedLocations} setTaguedLocations={setTaguedLocations}
                                     taguedObjects={taguedObjects} setTaguedObjects={setTaguedObjects}
                                     taguedWorldElements={taguedWorldElements}
                                     setTaguedWorldElements={setTaguedWorldElements}/>
                ) : !showTags && !advanceSettings ? (
                    <div className="p-4 lg:p-5 space-y-5 overflow-y-auto flex-grow custom-scrollbar">
                        <div className="bg-secondary/20 rounded-xl p-5 shadow-inner border border-secondary/30">
                            <h3 className="text-text-primary text-lg font-medium mb-4 flex items-center gap-2">
                                <FontAwesomeIcon icon={faHashtag} className="text-primary w-5 h-5"/>
                                {t("ghostWriter.length")}
                            </h3>
                            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                                <InputField
                                    fieldName={t("ghostWriter.minimum")}
                                    input={
                                        <NumberInput
                                            value={minWords}
                                            setValue={setMinWords}
                                            placeholder={t("ghostWriter.words")}
                                        />
                                    }
                                />
                                <InputField
                                    fieldName={t("ghostWriter.maximum")}
                                    input={
                                        <NumberInput
                                            value={maxWords}
                                            setValue={setMaxWords}
                                            placeholder={t("ghostWriter.words")}
                                        />
                                    }
                                />
                            </div>
                        </div>
                        
                        <div className="bg-secondary/20 rounded-xl p-5 shadow-inner border border-secondary/30">
                            <div className="mb-1">
                                <InputField
                                    icon={faBookOpen}
                                    fieldName={t("ghostWriter.type")}
                                    input={<RadioBox selected={type} setSelected={setType} name={'sectionType'}/>}
                                />
                            </div>
                        </div>
                        
                        <div className="bg-secondary/20 rounded-xl p-5 shadow-inner border border-secondary/30">
                            <InputField
                                icon={faPalette}
                                fieldName={t("ghostWriter.toneAtmosphere")}
                                input={
                                    <TextInput
                                        value={toneAtmosphere}
                                        setValue={(e: ChangeEvent<HTMLInputElement>) => setToneAtmosphere(e.target.value)}
                                        placeholder={t("ghostWriter.tonePlaceholder")}
                                    />
                                }
                            />
                        </div>
                        
                        <div className="bg-secondary/20 rounded-lg p-5 shadow-inner flex-1">
                            <InputField
                                icon={faMagicWandSparkles}
                                fieldName={t("ghostWriter.directive")}
                                action={importPrompt}
                                actionIcon={faFileImport}
                                actionLabel={t("ghostWriter.importPrompt")}
                                input={
                                    <TexteAreaInput
                                        value={directive}
                                        setValue={(e: ChangeEvent<HTMLTextAreaElement>) => setDirective(e.target.value)}
                                        placeholder={t("ghostWriter.directivePlaceholder")}
                                    />
                                }
                            />
                        </div>
                    </div>
                ) : advanceSettings && (
                    <GhostWriterSettings advancedPrompt={advancedPrompt} setAdvancedPrompt={setAdvancedPrompt}/>
                )
            }
            
            <div className="p-5 border-t border-secondary/50 bg-secondary/30 backdrop-blur-sm shrink-0 shadow-inner">
                <div className="flex justify-center gap-6">
                    <button
                        onClick={showAdvanceSetting}
                        className="px-6 py-3 rounded-xl font-medium text-base bg-secondary/50 hover:bg-secondary text-primary transition-all duration-200 flex items-center gap-2 shadow-md hover:shadow-lg hover:scale-105 border border-secondary/50"
                    >
                        <FontAwesomeIcon icon={advanceSettings ? faFloppyDisk : faGear} className={'w-5 h-5'}/>
                        <span>{advanceSettings ? t("ghostWriter.save") : t("ghostWriter.advanced")}</span>
                    </button>
                    {
                        advanceSettings && (
                            <button
                                onClick={(): void => setAdvanceSettings(false)}
                                className="px-6 py-3 rounded-xl font-medium text-base bg-secondary/50 hover:bg-secondary text-error transition-all duration-200 flex items-center gap-2 shadow-md hover:shadow-lg hover:scale-105 border border-secondary/50"
                            >
                                <FontAwesomeIcon icon={faX} className={'w-5 h-5'}/>
                                <span>{t("ghostWriter.cancel")}</span>
                            </button>
                        )
                    }
                    <button
                        onClick={(): void => setShowTags(!showTags)}
                        className="px-6 py-3 rounded-xl font-medium text-base bg-secondary/50 hover:bg-secondary text-primary transition-all duration-200 flex items-center gap-2 shadow-md hover:shadow-lg hover:scale-105 border border-secondary/50"
                    >
                        <FontAwesomeIcon icon={faTags} className={'w-5 h-5'}/>
                        <span>{t("ghostWriter.tags.addTagPlaceholder")}</span>
                    </button>

                    <SubmitButtonWLoading
                        callBackAction={handleGenerateGhostWriter}
                        isLoading={isGenerating}
                        text={t("ghostWriter.generate")}
                        loadingText={t("ghostWriter.generating")}
                        icon={faMagicWandSparkles}
                    />
                </div>
            </div>
            {(isTextGenerated || isGenerating) && (
                <QSTextGeneratedPreview
                    onClose={(): void => setIsTextGenerated(false)}
                    onRefresh={(): Promise<void> => handleGenerateGhostWriter()}
                    value={textGenerated}
                    onInsert={insertText}
                    isGenerating={isGenerating}
                    onStop={handleStopGeneration}
                />
            )}
        </div>
    );
}