'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */

/* eslint jsx-a11y/no-static-element-interactions: warn */
import { useAuth, useClerk } from '@clerk/nextjs';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
import { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next';

import { useStores } from '@/app/(root)/AppProviders';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { useDialogModal } from '@/components/modal/DialogModal';
import { useComments } from '@/hooks/useComments';
import {
  CloseIcon,
  HeartIcon,
  HeartOutlineIcon,
  MoreHorizontalIcon,
} from '@/icons';
import logWebUserEvent from '@/logging/logWebUserEvent';
import {
  CommentEntity,
  CommentEntityType,
  CommentSortBy,
} from '@/state/clipStore';
import { SIGNUP_SOURCE_PARAM, SIGNUP_SOURCE_VALUES } from '@/utils/constants';
import { formatRelativeTime } from '@/utils/time';
import { encodeTimeFormat, getClerkSignInRedirectProps } from '@/utils/utils';

export type Props = {
  isOpen: boolean;
  onClose: () => void;
  clipId: string;
  allowComments?: boolean | null;
  numComments?: number;
  isUserContentOwner?: boolean;
  deeplinkedCommentId?: string;
  entityType: CommentEntityType;
};

const MobileCommentsModal: React.FC<Props> = observer((props) => {
  const {
    isOpen,
    onClose,
    clipId,
    allowComments: clipAllowComment,
    numComments: _clipNumComments,
    isUserContentOwner = false,
    deeplinkedCommentId,
    entityType,
  } = props;

  const { t } = useTranslation();
  const { isSignedIn } = useAuth();
  const clerk = useClerk();
  const pathname = usePathname();
  const { session, playbar } = useStores();

  const [userCommentText, setUserCommentText] = useState('');
  const [replyToComment, setReplyToComment] = useState<{
    id: string;
    entityType: CommentEntityType;
  } | null>(null);
  const [lockedTrackTime, setLockedTrackTime] = useState<number | null>(null);
  const [expandedComments, setExpandedComments] = useState<Set<string>>(
    new Set()
  );

  // Swipe state
  const [modalHeight, setModalHeight] = useState<'2/3' | '7/8'>('2/3');
  const [isDragging, setIsDragging] = useState(false);
  const [startY, setStartY] = useState(0);
  const [currentY, setCurrentY] = useState(0);

  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const modalRef = useRef<HTMLDivElement>(null);

  const {
    comments,
    numComments,
    allowComments: commentsAllowComment,
    query: commentsQuery,
    reactionMutation,
    commentMutation,
    deleteMutation,
    reportMutation,
  } = useComments({
    entityId: clipId,
    entityType,
    sortBy: CommentSortBy.Newest,
    deeplinkedCommentId,
    refetchOnMount: 'always',
  });

  const { launchDialog } = useDialogModal();

  const allowComments = clipAllowComment ?? commentsAllowComment;

  // Swipe handlers
  const handleTouchStart = useCallback((e: React.TouchEvent) => {
    setIsDragging(true);
    setStartY(e.touches[0].clientY);
    setCurrentY(e.touches[0].clientY);
  }, []);

  const handleTouchMove = useCallback(
    (e: React.TouchEvent) => {
      if (!isDragging) return;
      setCurrentY(e.touches[0].clientY);
    },
    [isDragging]
  );

  const handleTouchEnd = useCallback(() => {
    if (!isDragging) return;

    const deltaY = startY - currentY;
    const threshold = 50; // Minimum swipe distance
    const closeThreshold = 100; // Threshold for closing the modal

    if (deltaY > threshold && modalHeight === '2/3') {
      // Swipe up - expand to 7/8
      setModalHeight('7/8');
    } else if (deltaY < -threshold) {
      // Swipe down - either contract or close
      if (modalHeight === '7/8') {
        setModalHeight('2/3');
      } else if (modalHeight === '2/3' && deltaY < -closeThreshold) {
        // Close modal when swiped down from 2/3 position
        onClose();
      }
    }

    setIsDragging(false);
  }, [isDragging, startY, currentY, modalHeight, onClose]);

  // Lock track time when user starts typing
  const lockTrackTimeIfNeeded = useCallback(
    (shouldLock: boolean) => {
      if (shouldLock && lockedTrackTime === null) {
        setLockedTrackTime(playbar.currentTime || 0);
      }
    },
    [lockedTrackTime, playbar.currentTime]
  );

  // Unlock track time when comment is empty
  const unlockTrackTimeIfNeeded = useCallback(
    (shouldUnlock: boolean) => {
      if (shouldUnlock && lockedTrackTime !== null) {
        setLockedTrackTime(null);
      }
    },
    [lockedTrackTime]
  );

  const handleTextChange = useCallback(
    (value: string) => {
      const commentWasEmpty = !userCommentText.trim();
      const commentIsEmpty = !value.trim();

      setUserCommentText(value);

      lockTrackTimeIfNeeded(commentWasEmpty && !commentIsEmpty);
      unlockTrackTimeIfNeeded(commentIsEmpty);
    },
    [userCommentText, lockTrackTimeIfNeeded, unlockTrackTimeIfNeeded]
  );

  const handleSendComment = useCallback(async () => {
    if (!userCommentText.trim()) return;

    if (!isSignedIn) {
      logWebUserEvent({
        actionName: 'CommentsOnSongPageSignUpPrompt',
        context: {
          entityId: clipId,
          entityType,
          numComments,
        },
      });
      clerk.openSignIn({
        withSignUp: true,
        ...getClerkSignInRedirectProps(
          `${pathname}?${SIGNUP_SOURCE_PARAM}=${SIGNUP_SOURCE_VALUES.SONG_PAGE}`
        ),
      });
      return;
    }

    try {
      await commentMutation.mutateAsync({
        content: userCommentText.trim(),
        commentId: replyToComment?.id,
        commentEntityType: replyToComment?.entityType,
        trackTimestamp:
          lockedTrackTime && lockedTrackTime > 0 ? lockedTrackTime : null,
      });

      setUserCommentText('');
      setReplyToComment(null);
      setLockedTrackTime(null);

      logWebUserEvent({
        actionName: 'CommentsOnSongPageClicked',
        context: {
          clipId,
          numComments,
        },
      });
    } catch (error) {
      console.error('Failed to post comment:', error);
    }
  }, [
    userCommentText,
    clipId,
    entityType,
    replyToComment,
    lockedTrackTime,
    commentMutation,
    isSignedIn,
    clerk,
    pathname,
    numComments,
  ]);

  const handleReplyToComment = useCallback(
    (id: string, entityType: CommentEntityType) => {
      setReplyToComment({ id, entityType });
      setTimeout(() => {
        textareaRef.current?.focus();
      }, 100);
    },
    []
  );

  const handleClearReply = useCallback(() => {
    setReplyToComment(null);
  }, []);

  const handleExpandComment = useCallback((commentId: string) => {
    setExpandedComments((prev) => new Set([...prev, commentId]));
  }, []);

  // Auto-resize textarea
  const handleTextareaInput = useCallback(
    (e: React.FormEvent<HTMLTextAreaElement>) => {
      const target = e.target as HTMLTextAreaElement;
      target.style.height = 'auto';
      target.style.height = `${Math.min(target.scrollHeight, 80)}px`;
    },
    []
  );

  // Close modal on backdrop click
  useEffect(() => {
    if (!isOpen) return;

    const handleClickOutside = (event: MouseEvent) => {
      if (
        modalRef.current &&
        !modalRef.current.contains(event.target as Node)
      ) {
        onClose();
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, [isOpen, onClose]);

  // Handle escape key
  useEffect(() => {
    if (!isOpen) return;

    const handleEscape = (event: KeyboardEvent) => {
      if (event.key === 'Escape') {
        onClose();
      }
    };

    document.addEventListener('keydown', handleEscape);
    return () => document.removeEventListener('keydown', handleEscape);
  }, [isOpen, onClose]);

  // Track modal open state for playbar hiding and body scroll locking
  useEffect(() => {
    // Update playbar store with modal state
    playbar.setIsMobileCommentsModalOpen(isOpen);

    // Reset to 2/3 height when modal opens or closes
    if (isOpen) {
      setModalHeight('2/3');
    } else {
      // Reset height when modal closes to prevent bounce on reopen
      setModalHeight('2/3');
    }

    // Lock/unlock body scroll when modal opens/closes
    if (typeof window !== 'undefined') {
      if (isOpen) {
        // Store current scroll position
        const scrollY = window.scrollY;
        document.body.style.overflow = 'hidden';
        // Only set position fixed if not in fullscreen mode
        if (
          !document.fullscreenElement &&
          !(document as any).webkitFullscreenElement &&
          !(document as any).mozFullScreenElement &&
          !(document as any).msFullscreenElement
        ) {
          document.body.style.position = 'fixed';
          document.body.style.top = `-${scrollY}px`;
          document.body.style.width = '100%';
        }
      } else {
        // Restore scroll position
        const scrollY = document.body.style.top;
        document.body.style.overflow = '';
        document.body.style.position = '';
        document.body.style.top = '';
        document.body.style.width = '';
        if (scrollY) {
          window.scrollTo(0, parseInt(scrollY || '0') * -1);
        }
      }
    }

    // Cleanup function to restore scroll when component unmounts
    return () => {
      if (typeof window !== 'undefined') {
        const scrollY = document.body.style.top;
        document.body.style.overflow = '';
        document.body.style.position = '';
        document.body.style.top = '';
        document.body.style.width = '';
        if (scrollY) {
          window.scrollTo(0, parseInt(scrollY || '0') * -1);
        }
      }
    };
  }, [isOpen, playbar]);

  if (!isOpen) return null;

  const replyComment = replyToComment
    ? comments.find(
        (c) =>
          c.id === replyToComment.id &&
          c.entityType === replyToComment.entityType
      )
    : null;

  const modalContent = (
    <div
      className='fixed inset-0 flex items-end justify-center bg-transparent'
      style={{ zIndex: 999999 }}
    >
      <div
        ref={modalRef}
        className='flex w-full flex-col rounded-t-3xl bg-background-primary transition-all duration-500 ease-out'
        style={{
          transform: `translateY(${isOpen ? '0' : '100%'})`,
          height: modalHeight === '2/3' ? '66.67vh' : '87.5vh',
        }}
        onTouchStart={handleTouchStart}
        onTouchMove={handleTouchMove}
        onTouchEnd={handleTouchEnd}
      >
        {/* Handle indicator */}
        <div className='flex cursor-grab justify-center pt-3 pb-2 active:cursor-grabbing'>
          <div className='h-1 w-9 rounded-full bg-background-secondary opacity-40' />
        </div>

        {/* Header */}
        <div className='flex items-center justify-between px-4 pb-4'>
          <div className='flex-1 text-center'>
            <h2 className='text-lg font-medium text-foreground-primary'>
              {numComments ? `Comments (${numComments})` : 'Comments'}
            </h2>
          </div>
          <Button
            variant={ButtonVariant.Tertiary}
            size={ButtonSize.Mini}
            shape={ButtonShape.Rounded}
            icon={CloseIcon}
            onClick={onClose}
            aria-label='Close comments'
            className='absolute right-4'
          />
        </div>

        <div className='mx-4 mb-6 h-px bg-foreground-tertiary' />

        {/* Comments List */}
        <div className='flex-1 overflow-y-auto'>
          {commentsQuery.isLoading ? (
            <div className='flex items-center justify-center py-16'>
              <div className='border-accent-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent' />
            </div>
          ) : comments.length === 0 ? (
            <div className='px-4 py-16 text-center opacity-50'>
              <h3 className='mb-2 text-2xl font-light text-foreground-primary'>
                No comments yet!
              </h3>
              <p className='mx-auto max-w-[250px] text-sm text-foreground-secondary'>
                Show your love with the first comment
              </p>
            </div>
          ) : (
            <div className='px-4 pb-8'>
              {comments.map((comment) => (
                <CommentItem
                  key={comment.id}
                  comment={comment}
                  isCommentByCurrentUser={comment.userId === session.userId}
                  isClipByCurrentUser={isUserContentOwner}
                  currentUserId={session.userId}
                  hasExpandedLongComment={expandedComments.has(comment.id)}
                  parentEntityType={entityType}
                  onReply={() =>
                    handleReplyToComment(comment.id, comment.entityType)
                  }
                  onLike={() => {
                    reactionMutation.mutate({
                      commentId: comment.id,
                      commentEntityType: comment.entityType,
                      isLike: comment.reactionType !== 'like',
                    });
                  }}
                  onExpandLongComment={() => handleExpandComment(comment.id)}
                  onReport={(reason) => {
                    reportMutation.mutate({
                      commentId: comment.id,
                      commentEntityType: comment.entityType,
                      reason,
                    });
                  }}
                  onDelete={() => {
                    launchDialog(t('comments.confirmDelete'), [
                      { label: t('cta.confirm'), action: true },
                      { label: t('cta.cancel'), action: false },
                    ]).then((confirmed) => {
                      if (confirmed) {
                        deleteMutation.mutate({
                          commentId: comment.id,
                          commentEntityType: comment.entityType,
                        });
                      }
                    });
                  }}
                />
              ))}
            </div>
          )}
        </div>

        {/* Reply indicator */}
        {replyComment && (
          <div className='bg-background-tertiary px-4 py-3'>
            <div className='flex items-center justify-between'>
              <div className='min-w-0 flex-1'>
                <div className='text-sm text-foreground-secondary'>
                  Replying to {replyComment.userDisplayName}
                </div>
                <div className='truncate text-sm text-foreground-tertiary opacity-50'>
                  {replyComment.content}
                </div>
              </div>
              <Button
                variant={ButtonVariant.Tertiary}
                size={ButtonSize.Mini}
                shape={ButtonShape.Rounded}
                icon={CloseIcon}
                onClick={handleClearReply}
                aria-label='Cancel reply'
              />
            </div>
          </div>
        )}

        <div className='h-px bg-foreground-tertiary' />

        {/* Input Area */}
        {allowComments ? (
          <div className='p-4'>
            <div className='flex items-end gap-3'>
              {/* Avatar */}
              <div className='h-10 w-10 shrink-0 overflow-hidden rounded-full bg-background-secondary'>
                {session.user?.avatar_image_url && (
                  <Image
                    src={session.user.avatar_image_url}
                    alt='Your avatar'
                    width={40}
                    height={40}
                    className='h-full w-full object-cover'
                  />
                )}
              </div>

              {/* Input Container */}
              <div className='relative flex-1'>
                <div className='flex min-h-[44px] items-center rounded-full bg-background-secondary px-4 py-3'>
                  <textarea
                    ref={textareaRef}
                    value={userCommentText}
                    onChange={(e) => handleTextChange(e.target.value)}
                    onInput={handleTextareaInput}
                    placeholder='Add a comment...'
                    className={clsx(
                      'w-full resize-none bg-transparent outline-none',
                      'text-[16px] text-foreground-primary placeholder-foreground-tertiary',
                      'max-h-20 overflow-y-auto leading-5'
                    )}
                    rows={1}
                    maxLength={500}
                    style={{ height: 'auto' }}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && !e.shiftKey) {
                        e.preventDefault();
                        handleSendComment();
                      }
                    }}
                  />

                  {/* Track Time Display */}
                  {lockedTrackTime !== null && lockedTrackTime > 0 && (
                    <div className='px-2 text-xs text-foreground-inactive'>
                      {encodeTimeFormat(lockedTrackTime)}
                    </div>
                  )}

                  {/* Send Button */}
                  {userCommentText.trim() && (
                    <div className='ml-2'>
                      <div
                        className={clsx(
                          'flex h-9 w-9 cursor-pointer items-center justify-center rounded-full bg-foreground-primary',
                          commentMutation.isPending &&
                            'cursor-not-allowed opacity-50'
                        )}
                        onClick={
                          commentMutation.isPending
                            ? undefined
                            : handleSendComment
                        }
                      >
                        <svg
                          width='16'
                          height='16'
                          viewBox='0 0 16 16'
                          fill='none'
                          className='rotate-90 transform text-background-primary'
                        >
                          <path
                            d='M8 3L8 13M3 8L13 8'
                            stroke='currentColor'
                            strokeWidth='2'
                            strokeLinecap='round'
                          />
                        </svg>
                      </div>
                    </div>
                  )}
                </div>
              </div>
            </div>
          </div>
        ) : (
          <div className='p-4 text-center'>
            <div className='bg-background-quaternary rounded-2xl py-4'>
              <p className='text-sm text-foreground-tertiary'>
                Comments are disabled for this clip.
              </p>
            </div>
          </div>
        )}
      </div>
    </div>
  );

  return typeof window !== 'undefined'
    ? createPortal(modalContent, document.body)
    : modalContent;
});

// Comment Item Component
const CommentItem: React.FC<{
  comment: CommentEntity;
  isCommentByCurrentUser: boolean;
  isClipByCurrentUser: boolean;
  currentUserId: string | null;
  hasExpandedLongComment: boolean;
  parentEntityType: CommentEntityType;
  onReply: () => void;
  onLike: () => void;
  onExpandLongComment: () => void;
  onReport: (reason: string) => void;
  onDelete: () => void;
}> = ({
  comment,
  isCommentByCurrentUser,
  isClipByCurrentUser,
  currentUserId,
  hasExpandedLongComment,
  parentEntityType,
  onReply,
  onLike,
  onExpandLongComment,
  onReport,
  onDelete,
}) => {
  const [showMoreMenu, setShowMoreMenu] = useState(false);

  const SHORT_CONTENT_LENGTH = 128;
  const isLongComment = comment.content.length >= SHORT_CONTENT_LENGTH;
  const shouldTruncate = isLongComment && !hasExpandedLongComment;

  const displayContent = shouldTruncate
    ? comment.content.substring(0, SHORT_CONTENT_LENGTH) + '...'
    : comment.content;

  return (
    <div className='py-3'>
      <div className='flex items-start gap-3'>
        {/* Avatar */}
        <div className='mt-1 h-8 w-8 shrink-0 overflow-hidden rounded-full bg-background-secondary'>
          {comment.userAvatarUrl && (
            <Image
              src={comment.userAvatarUrl}
              alt={`${comment.userDisplayName}'s avatar`}
              width={32}
              height={32}
              className='h-full w-full object-cover'
            />
          )}
        </div>

        {/* Content */}
        <div className='min-w-0 flex-1'>
          {/* Header */}
          <div className='mb-1 flex flex-wrap items-center gap-1'>
            <span className='line-clamp-1 text-sm font-medium text-foreground-primary'>
              {comment.userDisplayName}
            </span>

            {isCommentByCurrentUser && (
              <span className='rounded bg-background-secondary px-2 py-0.5 text-xs font-medium text-foreground-primary'>
                You
              </span>
            )}
            {!isCommentByCurrentUser &&
              isClipByCurrentUser &&
              comment.userId === currentUserId && (
                <span className='rounded bg-background-secondary px-2 py-0.5 text-xs font-medium text-foreground-primary'>
                  Creator
                </span>
              )}

            <span className='text-xs text-foreground-tertiary'>
              {formatRelativeTime(
                new Date(comment.createdAt).getTime() - Date.now(),
                'narrow',
                'just now'
              )}
            </span>

            {/* Show timestamp for clip context, or entity label for hook context */}
            {parentEntityType === 'clip' &&
              comment.trackTimestamp &&
              comment.trackTimestamp >= 1 && (
                <span className='text-xs font-medium text-accent-brand'>
                  at {encodeTimeFormat(comment.trackTimestamp)}
                </span>
              )}
            {parentEntityType === 'hook' && (
              <span className='text-xs font-medium text-accent-brand'>
                {comment.entityType === 'clip' ? 'on Song' : ''}
              </span>
            )}
          </div>

          {/* Comment Content */}
          <div className='mb-2'>
            <div
              className={clsx(
                'text-sm leading-tight text-foreground-primary',
                shouldTruncate && 'cursor-pointer'
              )}
              onClick={shouldTruncate ? onExpandLongComment : undefined}
            >
              {displayContent}
            </div>

            {shouldTruncate && (
              <button
                onClick={onExpandLongComment}
                className='text-foreground-link mt-1 text-xs'
              >
                Read more
              </button>
            )}
          </div>

          {/* Actions */}
          <div className='flex items-center justify-between'>
            <button
              onClick={onReply}
              className='text-xs font-medium text-foreground-tertiary'
            >
              Reply
            </button>

            <div className='flex items-center gap-4'>
              {/* Like Button */}
              <div className='flex flex-col items-center'>
                <Button
                  variant={ButtonVariant.Tertiary}
                  size={ButtonSize.Mini}
                  shape={ButtonShape.Rounded}
                  icon={
                    comment.reactionType === 'like'
                      ? HeartIcon
                      : HeartOutlineIcon
                  }
                  onClick={onLike}
                  className={clsx(
                    'h-6 w-6',
                    comment.reactionType === 'like' &&
                      'text-accent-pink-on-primary'
                  )}
                />
                {comment.numLikes > 0 && (
                  <span className='font-mono text-xs leading-tight text-foreground-tertiary'>
                    {comment.numLikes}
                  </span>
                )}
              </div>

              {/* More Menu */}
              <div className='relative'>
                <Button
                  variant={ButtonVariant.Tertiary}
                  size={ButtonSize.Mini}
                  shape={ButtonShape.Rounded}
                  icon={MoreHorizontalIcon}
                  onClick={() => setShowMoreMenu(!showMoreMenu)}
                  className='h-6 w-6'
                />

                {showMoreMenu && (
                  <>
                    {/* Backdrop */}
                    <div
                      className='fixed inset-0 z-10'
                      onClick={() => setShowMoreMenu(false)}
                    />

                    {/* Menu */}
                    <div className='absolute top-8 right-0 z-20 min-w-[120px] rounded-lg border border-border-primary bg-background-secondary py-1 shadow-lg'>
                      <button
                        onClick={() => {
                          onReply();
                          setShowMoreMenu(false);
                        }}
                        className='w-full px-3 py-2 text-left text-sm text-foreground-primary hover:bg-background-tertiary'
                      >
                        Reply
                      </button>

                      {(isCommentByCurrentUser || isClipByCurrentUser) && (
                        <button
                          onClick={() => {
                            onDelete();
                            setShowMoreMenu(false);
                          }}
                          className='w-full px-3 py-2 text-left text-sm text-accent-error-on-primary hover:bg-background-tertiary'
                        >
                          Delete
                        </button>
                      )}

                      {!isCommentByCurrentUser && (
                        <button
                          onClick={() => {
                            onReport('inappropriate');
                            setShowMoreMenu(false);
                          }}
                          className='w-full px-3 py-2 text-left text-sm text-accent-error-on-primary hover:bg-background-tertiary'
                        >
                          Report
                        </button>
                      )}
                    </div>
                  </>
                )}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default MobileCommentsModal;
