"use client";

import {
    useCallback,
    useEffect,
    useState,
} from "react";

import {
    createCommentType,
    deleteCommentType,
    getCommentTypes,
    updateCommentType,
} from "../service/comment-types-service";

import type {
    CommentType,
    CommentTypeFormValue,
} from "../types/comment-types-types";

function getErrorMessage(
    error: unknown,
    fallbackMessage: string,
): string {
    return error instanceof Error
        ? error.message
        : fallbackMessage;
}

export function useCommentTypes() {
    const [commentTypes, setCommentTypes] = useState<CommentType[]>([]);
    const [isLoading, setIsLoading] = useState(true);
    const [isCreating, setIsCreating] = useState(false);
    const [isUpdating, setIsUpdating] = useState(false);
    const [isDeleting, setIsDeleting] = useState(false);
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        let isMounted = true;

        async function loadInitialCommentTypes() {
            try {
                const data = await getCommentTypes();

                if (!isMounted) {
                    return;
                }

                setCommentTypes(data);
                setError(null);
            } catch (requestError) {
                if (!isMounted) {
                    return;
                }

                setError(
                    getErrorMessage(
                        requestError,
                        "Unable to load comment types.",
                    ),
                );
            } finally {
                if (isMounted) {
                    setIsLoading(false);
                }
            }
        }

        void loadInitialCommentTypes();

        return () => {
            isMounted = false;
        };
    }, []);

    /*
     * ប្រើសម្រាប់ refresh data ដោយ manual
     * ឧទាហរណ៍ក្រោយ create, update ឬ retry។
     */
    const fetchCommentTypes = useCallback(async () => {
        setIsLoading(true);
        setError(null);

        try {
            const data = await getCommentTypes();

            setCommentTypes(data);

            return data;
        } catch (requestError) {
            const message = getErrorMessage(
                requestError,
                "Unable to load comment types.",
            );

            setError(message);

            throw requestError;
        } finally {
            setIsLoading(false);
        }
    }, []);

    const addCommentType = useCallback(
        async (value: CommentTypeFormValue) => {
            setIsCreating(true);
            setError(null);

            try {
                const created = await createCommentType(value);

                setCommentTypes((current) => [
                    created,
                    ...current.filter(
                        (item) => item.id !== created.id,
                    ),
                ]);

                return created;
            } catch (requestError) {
                const message = getErrorMessage(
                    requestError,
                    "Unable to create comment type.",
                );

                setError(message);

                throw requestError;
            } finally {
                setIsCreating(false);
            }
        },
        [],
    );

    const editCommentType = useCallback(
        async (
            id: number,
            value: CommentTypeFormValue,
        ) => {
            setIsUpdating(true);
            setError(null);

            try {
                const updated = await updateCommentType(
                    id,
                    value,
                );

                setCommentTypes((current) =>
                    current.map((item) =>
                        item.id === id
                            ? updated
                            : item,
                    ),
                );

                return updated;
            } catch (requestError) {
                const message = getErrorMessage(
                    requestError,
                    "Unable to update comment type.",
                );

                setError(message);

                throw requestError;
            } finally {
                setIsUpdating(false);
            }
        },
        [],
    );

    const removeCommentType = useCallback(
        async (id: number) => {
            setIsDeleting(true);
            setError(null);

            try {
                await deleteCommentType(id);

                setCommentTypes((current) =>
                    current.filter(
                        (item) => item.id !== id,
                    ),
                );
            } catch (requestError) {
                const message = getErrorMessage(
                    requestError,
                    "Unable to delete comment type.",
                );

                setError(message);

                throw requestError;
            } finally {
                setIsDeleting(false);
            }
        },
        [],
    );

    return {
        commentTypes,
        isLoading,
        isCreating,
        isUpdating,
        isDeleting,
        error,
        fetchCommentTypes,
        addCommentType,
        editCommentType,
        removeCommentType,
    };
}