import {ChangeEvent, Dispatch, SetStateAction, useContext, useEffect, useState} from "react";
import {SelectBoxProps} from "@/shared/interface";
import {faCubes, faGlobe, faMapPin, faUser} from "@fortawesome/free-solid-svg-icons";
import System from "@/lib/models/System";
import {SessionContext} from "@/context/SessionContext";
import {AlertContext} from "@/context/AlertContext";
import {BookContext} from "@/context/BookContext";
import {BookTags} from "@/lib/models/Book";
import SuggestFieldInput from "@/components/form/SuggestFieldInput";
import {LangContext, LangContextProps} from "@/context/LangContext";
import {useTranslations} from "next-intl";

interface GhostWriterTagsProps {
    taguedCharacters: string[];
    setTaguedCharacters: Dispatch<SetStateAction<string[]>>;
    taguedLocations: string[];
    setTaguedLocations: Dispatch<SetStateAction<string[]>>;
    taguedObjects: string[];
    setTaguedObjects: Dispatch<SetStateAction<string[]>>;
    taguedWorldElements: string[];
    setTaguedWorldElements: Dispatch<SetStateAction<string[]>>;
}

export default function GhostWriterTags(
    {
        taguedCharacters,
        setTaguedCharacters,
        taguedLocations,
        setTaguedLocations,
        taguedObjects,
        setTaguedObjects,
        taguedWorldElements,
        setTaguedWorldElements
    }: GhostWriterTagsProps) {
    const {session} = useContext(SessionContext);
    const {errorMessage} = useContext(AlertContext);
    const t = useTranslations();
    const {lang} = useContext<LangContextProps>(LangContext)
    const {book} = useContext(BookContext);
    
    const [characters, setCharacters] = useState<SelectBoxProps[]>([]);
    const [locations, setLocations] = useState<SelectBoxProps[]>([]);
    const [objects, setObjects] = useState<SelectBoxProps[]>([]);
    const [worldElements, setWorldElements] = useState<SelectBoxProps[]>([]);
    
    const [searchCharacters, setSearchCharacters] = useState<string>('');
    const [searchLocations, setSearchLocations] = useState<string>('');
    const [searchObjects, setSearchObjects] = useState<string>('');
    const [searchWorldElements, setSearchWorldElements] = useState<string>('');
    
    const [showCharacterSuggestions, setShowCharacterSuggestions] = useState<boolean>(false);
    const [showLocationSuggestions, setShowLocationSuggestions] = useState<boolean>(false);
    const [showObjectSuggestions, setShowObjectSuggestions] = useState<boolean>(false);
    const [showWorldElementSuggestions, setShowWorldElementSuggestions] = useState<boolean>(false);
    
    useEffect((): void => {
        fetchData().then();
    }, []);
    
    async function fetchData(): Promise<void> {
        try {
            const tagsResponse: BookTags = await System.authGetQueryToServer<BookTags>(`book/tags`, session.accessToken, lang, {bookId: book?.bookId});
            if (tagsResponse) {
                setCharacters(tagsResponse.characters);
                setLocations(tagsResponse.locations);
                setObjects(tagsResponse.objects);
                setWorldElements(tagsResponse.worldElements);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('ghostwriter.tags.unknownError'));
            }
        }
    }
    
    function filteredCharacters(): SelectBoxProps[] {
        if (searchCharacters.trim().length === 0) return [];
        return characters
            .filter((item: SelectBoxProps): boolean =>
                item.label.toLowerCase().includes(searchCharacters.toLowerCase()) &&
                !taguedCharacters.includes(item.value)
            )
            .slice(0, 3);
    }
    
    function filteredLocations(): SelectBoxProps[] {
        if (searchLocations.trim().length === 0) return [];
        return locations
            .filter((item: SelectBoxProps): boolean =>
                item.label.toLowerCase().includes(searchLocations.toLowerCase()) &&
                !taguedLocations.includes(item.value)
            )
            .slice(0, 3);
    }
    
    function filteredObjects(): SelectBoxProps[] {
        if (searchObjects.trim().length === 0) return [];
        return objects
            .filter((item: SelectBoxProps): boolean =>
                item.label.toLowerCase().includes(searchObjects.toLowerCase()) &&
                !taguedObjects.includes(item.value)
            )
            .slice(0, 3);
    }
    
    function filteredWorldElements(): SelectBoxProps[] {
        if (searchWorldElements.trim().length === 0) return [];
        return worldElements
            .filter((item: SelectBoxProps): boolean =>
                item.label.toLowerCase().includes(searchWorldElements.toLowerCase()) &&
                !taguedWorldElements.includes(item.value)
            )
            .slice(0, 3);
    }
    
    function handleAddCharacter(value: string): void {
        if (!taguedCharacters.includes(value)) {
            const newCharacters: string[] = [...taguedCharacters, value];
            setTaguedCharacters(newCharacters);
        }
        setSearchCharacters('');
        setShowCharacterSuggestions(false);
    }
    
    function handleAddLocation(value: string): void {
        if (!taguedLocations.includes(value)) {
            const newLocations: string[] = [...taguedLocations, value];
            setTaguedLocations(newLocations);
        }
        setSearchLocations('');
        setShowLocationSuggestions(false);
    }
    
    function handleAddObject(value: string): void {
        if (!taguedObjects.includes(value)) {
            const newObjects: string[] = [...taguedObjects, value];
            setTaguedObjects(newObjects);
        }
        setSearchObjects('');
        setShowObjectSuggestions(false);
    }
    
    function handleAddWorldElement(value: string): void {
        if (!taguedWorldElements.includes(value)) {
            const newWorldElements: string[] = [...taguedWorldElements, value];
            setTaguedWorldElements(newWorldElements);
        }
        setSearchWorldElements('');
        setShowWorldElementSuggestions(false);
    }
    
    function handleRemoveCharacter(value: string): void {
        setTaguedCharacters(taguedCharacters.filter((tag: string): boolean => tag !== value));
    }
    
    function handleRemoveLocation(value: string): void {
        setTaguedLocations(taguedLocations.filter((tag: string): boolean => tag !== value));
    }
    
    function handleRemoveObject(value: string): void {
        setTaguedObjects(taguedObjects.filter((tag: string): boolean => tag !== value));
    }
    
    function handleRemoveWorldElement(value: string): void {
        setTaguedWorldElements(taguedWorldElements.filter((tag: string): boolean => tag !== value));
    }
    
    function handleCharacterSearch(text: string): void {
        setSearchCharacters(text);
        setShowCharacterSuggestions(text.trim().length > 0);
    }
    
    function handleLocationSearch(text: string): void {
        setSearchLocations(text);
        setShowLocationSuggestions(text.trim().length > 0);
    }
    
    function handleObjectSearch(text: string): void {
        setSearchObjects(text);
        setShowObjectSuggestions(text.trim().length > 0);
    }
    
    function handleWorldElementSearch(text: string): void {
        setSearchWorldElements(text);
        setShowWorldElementSuggestions(text.trim().length > 0);
    }
    
    function getCharacterLabel(value: string): string {
        const character: SelectBoxProps | undefined = characters.find((item: SelectBoxProps): boolean => item.value === value);
        return character ? character.label : value;
    }
    
    function getLocationLabel(value: string): string {
        const location: SelectBoxProps | undefined = locations.find((item: SelectBoxProps): boolean => item.value === value);
        return location ? location.label : value;
    }
    
    function getObjectLabel(value: string): string {
        const object: SelectBoxProps | undefined = objects.find((item: SelectBoxProps): boolean => item.value === value);
        return object ? object.label : value;
    }
    
    function getWorldElementLabel(value: string): string {
        const element: SelectBoxProps | undefined = worldElements.find((item: SelectBoxProps): boolean => item.value === value);
        return element ? element.label : value;
    }
    
    return (
        <div className="p-4 lg:p-5 space-y-4 overflow-y-auto flex-grow custom-scrollbar">
            <SuggestFieldInput inputFieldName={`Personnages`}
                               inputFieldIcon={faUser}
                               searchTags={searchCharacters}
                               tagued={taguedCharacters}
                               handleTagSearch={(e: ChangeEvent<HTMLInputElement>): void => handleCharacterSearch(e.target.value)}
                               handleAddTag={handleAddCharacter}
                               handleRemoveTag={handleRemoveCharacter}
                               filteredTags={filteredCharacters}
                               showTagSuggestions={showCharacterSuggestions}
                               setShowTagSuggestions={setShowCharacterSuggestions}
                               getTagLabel={getCharacterLabel}
            />
            
            <SuggestFieldInput inputFieldName={`Lieux`}
                               inputFieldIcon={faMapPin}
                               searchTags={searchLocations}
                               tagued={taguedLocations}
                               handleTagSearch={(e) => handleLocationSearch(e.target.value)}
                               handleAddTag={handleAddLocation}
                               handleRemoveTag={handleRemoveLocation}
                               filteredTags={filteredLocations}
                               showTagSuggestions={showLocationSuggestions}
                               setShowTagSuggestions={setShowLocationSuggestions}
                               getTagLabel={getLocationLabel}
            />
            
            <SuggestFieldInput inputFieldName={`Objets`}
                               inputFieldIcon={faCubes}
                               searchTags={searchObjects}
                               tagued={taguedObjects}
                               handleTagSearch={(e) => handleObjectSearch(e.target.value)}
                               handleAddTag={handleAddObject}
                               handleRemoveTag={handleRemoveObject}
                               filteredTags={filteredObjects}
                               showTagSuggestions={showObjectSuggestions}
                               setShowTagSuggestions={setShowObjectSuggestions}
                               getTagLabel={getObjectLabel}
            />
            
            <SuggestFieldInput inputFieldName={`Éléments mondiaux`}
                               inputFieldIcon={faGlobe}
                               searchTags={searchWorldElements}
                               tagued={taguedWorldElements}
                               handleTagSearch={(e) => handleWorldElementSearch(e.target.value)}
                               handleAddTag={handleAddWorldElement}
                               handleRemoveTag={handleRemoveWorldElement}
                               filteredTags={filteredWorldElements}
                               showTagSuggestions={showWorldElementSuggestions}
                               setShowTagSuggestions={setShowWorldElementSuggestions}
                               getTagLabel={getWorldElementLabel}
            />
        </div>
    );
}