import React, {ChangeEvent, useContext, useState} from 'react';
import {AlertTriangle, Plus, Trash2} from 'lucide-react';
import IconButton from "@/components/ui/IconButton";
import {Issue} from '@/lib/types/book';
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 {BookContext, BookContextProps} from '@/context/BookContext';
import {SessionContext, SessionContextProps} from '@/context/SessionContext';
import {AlertContext, AlertContextProps} from '@/context/AlertContext';
import Collapse from "@/components/ui/Collapse";
import TextInput from "@/components/form/TextInput";
import InputField from "@/components/form/InputField";
import {useTranslations} from '@/lib/i18n';
import {LangContext, LangContextProps} from "@/context/LangContext";

interface IssuesProps {
    issues: Issue[];
    setIssues: React.Dispatch<React.SetStateAction<Issue[]>>;
}

export default function Issues({issues, setIssues}: IssuesProps) {
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    const {book}: BookContextProps = useContext<BookContextProps>(BookContext);
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {errorMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {isCurrentlyOffline}: OfflineContextType = useContext<OfflineContextType>(OfflineContext);

    const bookId: string | undefined = book?.bookId;
    const token: string = session.accessToken;
    
    const [newIssueName, setNewIssueName] = useState<string>('');
    
    async function addNewIssue(): Promise<void> {
        if (newIssueName.trim() === '') {
            errorMessage(t("issues.errorEmptyName"));
            return;
        }
        try {
            let issueId: string;
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                issueId = await tauri.addIssue(bookId ?? '', newIssueName);
            } else {
                issueId = await apiPost<string>('book/issue/add', {
                    bookId,
                    name: newIssueName,
                }, token, lang);
            }
            if (!issueId) {
                errorMessage(t("issues.errorAdd"));
                return;
            }
            const newIssue: Issue = {
                name: newIssueName,
                id: issueId,
            };
            
            setIssues([...issues, newIssue]);
            setNewIssueName('');
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("issues.errorUnknownAdd"));
            }
        }
    }
    
    async function deleteIssue(issueId: string): Promise<void> {
        if (issueId === undefined) {
            errorMessage(t("issues.errorInvalidId"));
        }
        
        
        try {
            let response: boolean;
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                response = await tauri.removeIssue(bookId ?? '', issueId, Date.now());
            } else {
                response = await apiDelete<boolean>(
                    'book/issue/remove',
                    {
                        bookId,
                        issueId,
                    },
                    token,
                    lang
                );
            }
            if (response) {
                const updatedIssues: Issue[] = issues.filter((issue: Issue): boolean => issue.id !== issueId,);
                setIssues(updatedIssues);
            } else {
                errorMessage(t("issues.errorDelete"));
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("issues.errorUnknownDelete"));
            }
        }
    }
    
    function updateIssueName(issueId: string, name: string): void {
        const updatedIssues: Issue[] = issues.map((issue: Issue): Issue => {
            if (issue.id === issueId) {
                return {...issue, name};
            }
            return issue;
        });
        setIssues(updatedIssues);
    }
    
    return (
        <Collapse variant="card" title={t("issues.title")} icon={AlertTriangle}>
            <div className="space-y-2">
                {issues && issues.length > 0 ? (
                    issues.map(function (item: Issue): React.JSX.Element {
                        return (
                            <div key={`issue-${item.id}`} className="flex items-center gap-2">
                                <div className="flex-1">
                                    <TextInput
                                        value={item.name}
                                        setValue={function (e: ChangeEvent<HTMLInputElement>): void {
                                            updateIssueName(item.id, e.target.value);
                                        }}
                                        placeholder={t("issues.issueNamePlaceholder")}
                                    />
                                </div>
                                <IconButton icon={Trash2} variant="danger" size="sm"
                                            onClick={function (): Promise<void> {
                                                return deleteIssue(item.id);
                                            }}/>
                            </div>
                        );
                    })
                ) : (
                    <p className="text-text-secondary text-center py-2 text-sm">
                        {t("issues.noIssue")}
                    </p>
                )}
                <InputField
                    input={
                        <TextInput
                            value={newIssueName}
                            setValue={function (e: ChangeEvent<HTMLInputElement>): void {
                                setNewIssueName(e.target.value);
                            }}
                            placeholder={t("issues.newIssuePlaceholder")}
                        />
                    }
                    actionIcon={Plus}
                    addButtonCallBack={addNewIssue}
                    isAddButtonDisabled={newIssueName.trim() === ''}
                />
            </div>
        </Collapse>
    );
}