import { useStudyGroupContext } from '@/providers/StudyGroupContext';
import { AxiosErrorResponse, CommentLike, StudyGroupTaskComment } from '@/types';
import { errorMessageFormatter, stringAvatar, stringToColor } from '@/utils';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Avatar, Button, Card, Divider, Empty, Form, Pagination, Tooltip } from 'antd';
import dayjs from 'dayjs';
import { useTranslation } from 'next-i18next';
import { toast } from 'react-toastify';
import usePagination from '@/hooks/usePagination';
import {
    getOwnTaskComment,
    getStudyGroupTaskComments,
    getTaskCommentLikes,
    likeComment,
    scheduleComment,
    updateComment,
} from '@/services/study-group';
import { Editor } from '@tinymce/tinymce-react';
import { useEffect, useState } from 'react';
import { useMemberContext } from '@/providers/MemberContext';
import HtmlParser from '@/components/HtmlParser';
import { dateTimeTransformer, timeTransformer } from '@/utils/timeTransformer';
import { CommentOutlined, LikeFilled, LikeOutlined } from '@ant-design/icons';
import ReplyModal from '../modals/Reply';
import RenderReply from '../RenderReply';
import { v4 as uuid } from 'uuid';

const CommentTab: React.FC = () => {
    const { t, i18n } = useTranslation(['study-group-task', 'common']);
    const currentLocale = i18n.language;
    const { studyGroupTaskId, studyGroupTask } = useStudyGroupContext();
    const [pagination, setPagination] = usePagination();
    const [updateCommentForm] = Form.useForm();
    const { member } = useMemberContext();
    const queryClient = useQueryClient();

    const studyGroupTaskData = studyGroupTask.data;

    // State to track expanded comments and replies
    const [expandedCommentId, setExpandedCommentId] = useState<string | null>();
    const [expandedCommentIdArray, setExpandedCommentIdArray] = useState<string[]>([]);

    // State to track actions (Comment / Reply)
    const [action, setAction] = useState<string>();

    // Query
    const commentsQuery = useQuery({
        queryKey: ['comments', studyGroupTaskId, 'pagination', pagination],
        enabled: !!studyGroupTaskId,
        queryFn: async () => {
            const query = {
                page: pagination.page,
                pageSize: pagination.pageSize,
                sortField: pagination.sortField,
                sortOrder: pagination.sortOrder,
            };

            const res = await getStudyGroupTaskComments(studyGroupTaskId, query);

            // page count without parent_id
            const pageTotal = res.data?.total - res.data?.rows.filter((comment: StudyGroupTaskComment) => comment.parent_id).length;

            setPagination((prev) => {
                return {
                    ...prev,
                    page: res.data?.page,
                    total: pageTotal,
                };
            });

            return res.data?.rows;
        },
        onError: (error: AxiosErrorResponse & Error) => {
            toast.error(t(errorMessageFormatter(error)));
        },
    });
    const commentsData = commentsQuery.data;

    const ownCommentQuery = useQuery({
        queryKey: ['own-comment', studyGroupTaskId],
        enabled: !!studyGroupTaskId,
        queryFn: async () => {
            const res = await getOwnTaskComment(studyGroupTaskId);
            return res.data;
        },
        onError: (error: AxiosErrorResponse & Error) => {
            toast.error(t(errorMessageFormatter(error)));
        },
    });
    const ownCommentData = ownCommentQuery.data;

    // own member comment is always first while the other follow and remove ones with parent_id
    const commentList = (
        ownCommentData && commentsData ? (ownCommentData.prePlanned ? commentsData : [ownCommentData, ...commentsData]) : commentsData
    )?.filter((comment: StudyGroupTaskComment) => !comment.parent_id);

    const commentLikesQuery = useQuery({
        queryKey: ['comment-likes', studyGroupTaskId],
        enabled: !!studyGroupTaskId,
        queryFn: async () => {
            const res = await getTaskCommentLikes(studyGroupTaskId);

            return res.data;
        },
        onError: (error: AxiosErrorResponse & Error) => {
            toast.error(t(errorMessageFormatter(error)));
        },
    });
    const commentLikesData = commentLikesQuery.data;

    // Mutation for update comment
    const updateCommentMutation = useMutation({
        mutationFn: async () => {
            const comments = updateCommentForm.getFieldsValue().comment;

            const response = await updateComment(studyGroupTaskId, comments);

            return response.data;
        },
        onSuccess: () => {
            queryClient.invalidateQueries(['study-group-own-comment']);
            ownCommentQuery.refetch();
            commentsQuery.refetch();
            studyGroupTask.refetch();
            commentLikesQuery.refetch();
        },
    });

    // Mutation for scheduled comment
    const scheduleCommentMutation = useMutation({
        mutationFn: async () => {
            const values = updateCommentForm.getFieldsValue().comment;
            const response = await scheduleComment(studyGroupTaskId, values, studyGroupTaskData?.taskDate as string);

            return response.data;
        },
        onSuccess: () => {
            queryClient.invalidateQueries(['study-group-own-comment']);
            ownCommentQuery.refetch();
            commentsQuery.refetch();
            studyGroupTask.refetch();
            commentLikesQuery.refetch();
        },
    });

    // Mutation for like comment
    const likeCommentMutation = useMutation({
        mutationFn: async (studyGroupTaskCommentId: string) => {
            const response = await likeComment(studyGroupTaskCommentId, member?.id as string, studyGroupTaskId);

            return response.data;
        },
        onSuccess: () => {
            queryClient.invalidateQueries(['study-group-own-comment']);
            ownCommentQuery.refetch();
            commentsQuery.refetch();
            studyGroupTask.refetch();
            commentLikesQuery.refetch();
        },
    });

    // Fill in TinyMCE editor with comment of member
    useEffect(() => {
        if (member?.id && ownCommentData) {
            updateCommentForm.setFieldsValue({
                comment: ownCommentData.comment,
            });
        } else {
            updateCommentForm.setFieldsValue({
                comment: '',
            });
        }
    }, [member?.id, ownCommentData]);

    const gridStyleBody: React.CSSProperties = {
        width: '100%',
        textAlign: 'start',
        paddingBottom: 0,
    };

    const gridStyleFooter: React.CSSProperties = {
        width: '100%',
        textAlign: 'end',
        paddingTop: 16,
        paddingBottom: 16,
    };

    // Function
    const updateCommentHandler = () => {
        updateCommentForm.validateFields().then(() => {
            toast.promise(updateCommentMutation.mutateAsync(), {
                pending: t('common:updating-comment'),
                success: t('common:comment-updated'),
                error: {
                    render({ data }) {
                        return t(errorMessageFormatter(data as AxiosErrorResponse));
                    },
                },
            });
        });
    };

    const schedulePostHandler = () => {
        updateCommentForm.validateFields().then(() => {
            toast.promise(scheduleCommentMutation.mutateAsync(), {
                pending: t('common:pre-planning-comment'),
                success: t('common:comment-pre-planned'),
                error: {
                    render({ data }) {
                        return t(errorMessageFormatter(data as AxiosErrorResponse));
                    },
                },
            });
        });
    };

    const handleLike = async (studyGroupTaskCommentId: string) => {
        // Check if the comment is already liked by the user
        const alreadyLiked = commentLikesData?.some(
            (like: CommentLike) => like.studyGroupTaskCommentId === studyGroupTaskCommentId && like.memberId === member?.id,
        );

        // Perform like/unlike action based on the current state
        if (alreadyLiked) {
            // Unlike the comment
            await toast.promise(likeCommentMutation.mutateAsync(studyGroupTaskCommentId), {
                pending: t('common:unliking-comment'),
                success: t('common:comment-unliked'),
                error: {
                    render({ data }) {
                        return t(errorMessageFormatter(data as AxiosErrorResponse));
                    },
                },
            });
        } else {
            // Like the comment
            await toast.promise(likeCommentMutation.mutateAsync(studyGroupTaskCommentId), {
                pending: t('common:liking-comment'),
                success: t('common:comment-liked'),
                error: {
                    render({ data }) {
                        return t(errorMessageFormatter(data as AxiosErrorResponse));
                    },
                },
            });
        }
    };

    // Update the like count and icon based on the current state of likes
    const renderLikeButton = (comment: StudyGroupTaskComment) => {
        const liked = commentLikesData?.some((like: CommentLike) => like.studyGroupTaskCommentId === comment.id && like.memberId === member?.id);
        const likesCount = commentLikesData?.filter((like: CommentLike) => like.studyGroupTaskCommentId === comment.id).length;

        return (
            <div className="flex flex-row gap-1 items-center">
                <Tooltip title={liked ? t('common:unlike') : t('common:like')}>
                    <Button
                        type="text"
                        shape="circle"
                        size="middle"
                        icon={liked ? <LikeFilled style={{ color: '#597ef7' }} /> : <LikeOutlined />}
                        onClick={() => handleLike(comment.id)}
                        loading={likeCommentMutation.isLoading}
                    />
                </Tooltip>
                <span className="text-xs sm:text-sm ml-1">{likesCount}</span>
            </div>
        );
    };

    const handleSetExpandedCommentId = (commentId: string) => {
        setExpandedCommentId(commentId === expandedCommentId ? null : commentId);
        setExpandedCommentIdArray(
            expandedCommentIdArray.includes(commentId)
                ? expandedCommentIdArray.filter((id) => id !== commentId)
                : [...expandedCommentIdArray, commentId],
        );
    };

    const unformattedCurrentTime = dayjs.tz().toISOString();
    const currentTime = timeTransformer(unformattedCurrentTime);
    const restrictedTime = currentTime >= '00:00' && currentTime <= '05:00';

    const onResetHandler = () => {
        setAction('');
    };

    return (
        <div className="flex flex-col">
            <div className="w-full">
                <Form form={updateCommentForm} layout="vertical">
                    <div className="mb-2 text-[#343434] text-lg">
                        <b>{t('your-comment')}</b>
                    </div>
                    <Form.Item
                        name="comment"
                        trigger="onEditorChange"
                        className="w-full"
                        rules={[
                            {
                                required: action === 'comment' ? true : false,
                                message: t('comment-is-required', { field: t('common:comment') }),
                            },
                        ]}
                    >
                        <Editor
                            id={uuid()}
                            tinymceScriptSrc={'/tinymce/js/tinymce/tinymce.min.js'}
                            init={{
                                height: 200,
                                menubar: '',
                                plugins: ['advlist', 'autolink', 'lists', 'link', 'searchreplace', 'code', 'preview', 'wordcount', 'table', 'paste'],
                                toolbar:
                                    'undo redo | blocks | ' +
                                    'bold italic forecolor | link | alignleft aligncenter ' +
                                    'alignright alignjustify | bullist numlist outdent indent | ' +
                                    'fullscreen',
                                block_formats: 'Paragraph=p;Header 2=h2;Header 3=h3;Header 4=h4',
                                content_style: 'body { font-family:var(--font-ubuntu); font-size:14px; text-align:left }',
                                language: currentLocale === 'en-GB' ? undefined : currentLocale,
                                language_url: currentLocale === 'en-GB' ? undefined : '/editor-translation/' + currentLocale + '.js',
                                promotion: false,
                                paste_data_images: true,
                                contextmenu: false,
                            }}
                        />
                    </Form.Item>
                    {/* Schedule comment button */}
                    {dayjs.tz().isBefore(dayjs(studyGroupTaskData?.taskDate), 'day') && (
                        <Form.Item className="flex justify-end">
                            <Button type="primary" ghost onClick={schedulePostHandler} loading={scheduleCommentMutation.isLoading}>
                                {t('common:schedule-comment')}
                            </Button>
                        </Form.Item>
                    )}
                    {dayjs(studyGroupTaskData?.taskDate).tz().isSame(dayjs.tz(), 'day') &&
                        !restrictedTime &&
                        (ownCommentData ? (
                            <Form.Item className="flex justify-end">
                                <Button
                                    type="primary"
                                    onClick={() => {
                                        updateCommentHandler();
                                        setAction('comment');
                                    }}
                                    loading={updateCommentMutation.isLoading}
                                >
                                    {t('common:update-comment')}
                                </Button>
                            </Form.Item>
                        ) : (
                            <Form.Item className="flex justify-end">
                                <Button
                                    type="primary"
                                    onClick={() => {
                                        updateCommentHandler();
                                        setAction('comment');
                                    }}
                                    loading={updateCommentMutation.isLoading}
                                >
                                    {t('common:add-comment')}
                                </Button>
                            </Form.Item>
                        ))}
                </Form>
            </div>
            <div className="text-lg font-bold mb-2 ml-1">{t('comments')}</div>
            <Card.Grid style={gridStyleBody} hoverable={false}>
                {commentList && commentList.length !== 0 ? (
                    commentList.map((comment: StudyGroupTaskComment) => {
                        console.log(comment);
                        return <div key={comment.id} className="flex flex-col gap-2 mb-6 border-solid rounded-xl border-[#f5f5f5] hover:shadow-md">
                            <div className="p-4 pb-0">
                                <div className="flex flex-row gap-4">
                                    <div className="flex flex-col w-full mb-2">
                                        <div className="flex flex-row justify-between gap-2">
                                            <div className="flex flex-row gap-2 mb-2">
                                                {comment.member?.preferredName || comment.staff?.fullName ? (
                                                    <div className="font-semibold flex flex-row items-center gap-2">
                                                        <Avatar
                                                            style={{
                                                                backgroundColor: stringToColor(
                                                                    comment.member?.preferredName
                                                                        ? comment.member?.preferredName
                                                                        : comment.staff?.fullName,
                                                                ),
                                                            }}
                                                            size={30}
                                                            className="flex items-center flex-row gap-2"
                                                        >
                                                            {stringAvatar(
                                                                comment.member?.preferredName
                                                                    ? comment.member?.preferredName
                                                                    : comment.staff?.fullName,
                                                            )}
                                                        </Avatar>
                                                        <span className="text-xs sm:text-sm">
                                                            {comment.member?.preferredName ? comment.member?.preferredName : comment.staff?.fullName}
                                                        </span>
                                                    </div>
                                                ) : (
                                                    <div className="font-semibold flex flex-row items-center gap-2">
                                                        <Avatar
                                                            style={{
                                                                backgroundColor: stringToColor(
                                                                    comment.member?.fullName ? comment.member?.fullName : comment.staff?.fullName,
                                                                ),
                                                            }}
                                                            size={30}
                                                            className="flex items-center flex-row gap-2"
                                                        >
                                                            {stringAvatar(
                                                                comment.member?.fullName ? comment.member?.fullName : comment.staff?.fullName,
                                                            )}
                                                        </Avatar>
                                                        <span className="text-xs sm:text-sm">
                                                            {comment.member?.fullName ? comment.member?.fullName : comment.staff?.fullName}
                                                        </span>
                                                    </div>
                                                )}
                                                <div className="text-gray-400 flex items-center text-xs">
                                                    {dateTimeTransformer(comment.commentDate)}
                                                </div>
                                            </div>
                                        </div>
                                        <div className="text-xs sm:text-sm ml-[38px]">
                                            <HtmlParser html={comment.comment} />
                                        </div>
                                    </div>
                                </div>
                                <Divider className="my-0" />
                                <div className="flex flex-row items-center gap-x-8">
                                    <div className="flex flex-row gap-1 align-middle items-center py-1">{renderLikeButton(comment)}</div>
                                    <div className="flex flex-row gap-2">
                                        <Button type="text" icon={<CommentOutlined />} onClick={() => handleSetExpandedCommentId(comment.id)}>
                                            {t('replies') + ' (' + comment.Children.length + ')'}
                                        </Button>
                                    </div>
                                </div>
                            </div>
                            {expandedCommentIdArray.find((commentId: string) => {
                                return commentId === comment.id;
                            }) && (
                                <div className="p-4 pb-0 bg-gray-50 rounded-lg rounded-t-none">
                                    <div className="flex flex-col sm:flex-row sm:justify-between gap-4 sm:gap-0 mb-4">
                                        <div className="text-[#343434] text-lg flex items-center">
                                            <b>{t('replies') + ' (' + comment.Children.length + ')'}</b>
                                        </div>
                                        <ReplyModal onReset={onResetHandler} studyGroupTaskId={studyGroupTaskId} parentId={comment.id} />
                                    </div>
                                    <RenderReply studyGroupTaskId={studyGroupTaskId} commentId={comment.id} />
                                </div>
                            )}
                        </div>
                    })
                ) : (
                    <Empty description={t('common:no-comments-available')} className="mb-4" />
                )}
            </Card.Grid>
            {commentList && commentList.length !== 0 ? (
                <Card.Grid style={gridStyleFooter} hoverable={false}>
                    <div className="flex justify-end">
                        <Pagination
                            current={pagination.page}
                            pageSize={pagination.pageSize}
                            defaultPageSize={1}
                            showSizeChanger={true}
                            pageSizeOptions={[10, 25, 50, 100]}
                            total={ownCommentData?.prePlanned ? pagination.total : pagination.total + 1}
                            showTotal={(total, range) => {
                                return t('common:pagination', { range0: range[0], range1: range[1], total: total });
                            }}
                            onChange={(page, pageSize) => setPagination({ ...pagination, page, pageSize })}
                        />
                    </div>
                </Card.Grid>
            ) : null}
        </div>
    );
};

export default CommentTab;
