'use client';

import React, {ChangeEvent, useContext, useState} from "react";
import {WorldContext, WorldContextProps} from "@/context/WorldContext";
import TextInput from "@/components/form/TextInput";
import TextAreaInput from "@/components/form/TextAreaInput";
import {WorldElement, WorldElementSection, WorldProps} from "@/lib/types/world";
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
import {apiDelete, apiPost} from "@/lib/api/client";
import {isDesktop} from '@/lib/configs';
import * as tauri from '@/lib/tauri';
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';
import {BooksSyncContext, BooksSyncContextProps} from '@/context/BooksSyncContext';
import {SyncedBook} from '@/lib/types/synced-book';
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from '@/context/SyncQueueContext';
import {BookContext, BookContextProps} from '@/context/BookContext';
import InputField from "@/components/form/InputField";
import {useTranslations} from '@/lib/i18n';
import {LangContext, LangContextProps} from "@/context/LangContext";

interface WorldElementInputProps {
    sectionLabel: string;
    sectionType: WorldElementSection;
}

function getElementTypeNumber(sectionType: WorldElementSection): number {
    const typeMap: Record<WorldElementSection, number> = {
        'laws': 0,
        'biomes': 1,
        'issues': 2,
        'customs': 3,
        'kingdoms': 4,
        'climate': 5,
        'resources': 6,
        'wildlife': 7,
        'arts': 8,
        'ethnicGroups': 9,
        'socialClasses': 10,
        'importantCharacters': 11,
    };
    return typeMap[sectionType] ?? 0;
}

export default function WorldElementComponent({sectionLabel, sectionType}: WorldElementInputProps): React.JSX.Element {
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    const {
        worlds,
        setWorlds,
        selectedWorldIndex,
        isSeriesMode
    }: WorldContextProps = useContext<WorldContextProps>(WorldContext);
    const {errorMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {book}: BookContextProps = useContext<BookContextProps>(BookContext);
    const {isCurrentlyOffline}: OfflineContextType = useContext<OfflineContextType>(OfflineContext);
    const {addToQueue}: LocalSyncQueueContextProps = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
    const {localSyncedBooks}: BooksSyncContextProps = useContext<BooksSyncContextProps>(BooksSyncContext);

    const [newElementName, setNewElementName] = useState<string>('');

    async function handleRemoveElement(
        section: WorldElementSection,
        index: number,
    ): Promise<void> {
        try {
            const elements: WorldElement[] = worlds[selectedWorldIndex][section];
            let response: boolean;
            if (!isSeriesMode && isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                response = await tauri.removeWorldElement(elements[index].id, book?.bookId ?? '', Date.now());
            } else {
                const endpoint: string = isSeriesMode ? 'series/world/element/delete' : 'book/world/element/delete';
                response = await apiDelete<boolean>(endpoint, {
                    elementId: elements[index].id,
                }, session.accessToken, lang);
                if (!isSeriesMode && isDesktop && localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === book?.bookId)) {
                    addToQueue('remove_world_element', {elementId: elements[index].id, bookId: book?.bookId, deletedAt: Date.now()});
                }
            }
            if (!response) {
                errorMessage(t("worldSetting.unknownError"))
            }
            const updatedWorlds: WorldProps[] = [...worlds];
            updatedWorlds[selectedWorldIndex][section].splice(index, 1);
            setWorlds(updatedWorlds);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("worldElementComponent.errorUnknown"));
            }
        }
    }
    
    async function handleAddElement(section: WorldElementSection): Promise<void> {
        if (newElementName.trim() === '') {
            errorMessage(t("worldElementComponent.emptyField", {section: sectionLabel}));
            return;
        }
        try {
            let elementId: string;
            if (isSeriesMode) {
                elementId = await apiPost<string>(
                    'series/world/element/add',
                    {
                        worldId: worlds[selectedWorldIndex].id,
                        elementType: getElementTypeNumber(section),
                        name: newElementName,
                    },
                    session.accessToken,
                    lang
                );
                if (!elementId) {
                    errorMessage(t("worldSetting.unknownError"))
                    return;
                }
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                elementId = await tauri.addWorldElement(worlds[selectedWorldIndex].id, newElementName, section);
                if (!elementId) {
                    errorMessage(t("worldSetting.unknownError"))
                    return;
                }
            } else {
                elementId = await apiPost<string>('book/world/element/add', {
                    elementType: section,
                    worldId: worlds[selectedWorldIndex].id,
                    elementName: newElementName,
                }, session.accessToken, lang);
                if (isDesktop && localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === book?.bookId)) {
                    addToQueue('add_world_element', {worldId: worlds[selectedWorldIndex].id, elementId, elementType: section, elementName: newElementName});
                }
                if (!elementId) {
                    errorMessage(t("worldSetting.unknownError"))
                    return;
                }
            }
            const updatedWorlds: WorldProps[] = [...worlds];
            updatedWorlds[selectedWorldIndex][section].push({
                id: elementId,
                name: newElementName,
                description: '',
            });
            setWorlds(updatedWorlds);
            setNewElementName('');
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("worldElementComponent.errorUnknown"));
            }
        }
    }

    function handleElementChange(
        section: WorldElementSection,
        index: number,
        field: keyof WorldElement,
        value: string,
    ): void {
        const updatedWorlds: WorldProps[] = [...worlds];
        const sectionElements: WorldElement[] = updatedWorlds[selectedWorldIndex][section];
        sectionElements[index] = {...sectionElements[index], [field]: value};
        setWorlds(updatedWorlds);
    }
    
    return (
        <div className="space-y-4">
            {worlds[selectedWorldIndex][sectionType].map(
                (element: WorldElement, index: number): React.JSX.Element => (
                    <div key={element.id}
                         className="bg-secondary rounded-xl p-4 border-l-4 border-primary transition-colors duration-200">
                        <div className="mb-2">
                            <InputField input={<TextInput
                                value={element.name}
                                setValue={(e: ChangeEvent<HTMLInputElement>): void => handleElementChange(sectionType, index, 'name', e.target.value)}
                                placeholder={t("worldElementComponent.namePlaceholder", {section: sectionLabel.toLowerCase()})}
                            />}
                                        removeButtonCallBack={(): Promise<void> => handleRemoveElement(sectionType, index)}/>
                        </div>
                        <TextAreaInput
                            value={element.description}
                            setValue={(e: ChangeEvent<HTMLTextAreaElement>): void => handleElementChange(sectionType, index, 'description', e.target.value)}
                            placeholder={t("worldElementComponent.descriptionPlaceholder", {section: sectionLabel.toLowerCase()})}
                        />
                    </div>
                )
            )}
            <InputField input={<TextInput
                value={newElementName}
                setValue={(e: ChangeEvent<HTMLInputElement>): void => setNewElementName(e.target.value)}
                placeholder={t("worldElementComponent.newPlaceholder", {section: sectionLabel.toLowerCase()})}
            />} addButtonCallBack={(): Promise<void> => handleAddElement(sectionType)}/>
        </div>
    );
}
