import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { formatDistanceToNow } from 'date-fns';
import { fr } from 'date-fns/locale';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Avatar } from '@/components/ui/avatar';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { ConfirmationDialog } from '@/components/ui/confirmation-dialog';
import {
  MessageCircle,
  Reply,
  Trash2,
  Edit2,
  MoreVertical,
  Send,
  X,
  Loader2,
} from 'lucide-react';
import { useUser } from '@/features/auth/hooks/useUser';
import { useToast } from '@/hooks/useToast';
import {
  createComment,
  updateComment,
  deleteComment,
  getReplies,
  type TrackComment,
  type CommentListResponse,
  type ReplyListResponse,
} from '../services/commentService';
import { cn } from '@/lib/utils';

/**
 * FE-COMP-012: Comment thread component with replies and moderation
 */

interface CommentThreadProps {
  comment: TrackComment;
  trackId: string;
  depth?: number;
  className?: string;
}

const MAX_DEPTH = 3; // Maximum nesting depth for replies

export function CommentThread({
  comment,
  trackId,
  depth = 0,
  className,
}: CommentThreadProps) {
  const { data: user } = useUser();
  const { success: showSuccess, error: showError } = useToast();
  const queryClient = useQueryClient();
  const [isReplying, setIsReplying] = useState(false);
  const [isEditing, setIsEditing] = useState(false);
  const [replyContent, setReplyContent] = useState('');
  const [editContent, setEditContent] = useState(comment.content);
  const [showReplies, setShowReplies] = useState(depth === 0);
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);

  // Fetch replies
  const { data: repliesData, isLoading: isLoadingReplies } = useQuery({
    queryKey: ['commentReplies', comment.id],
    queryFn: () => getReplies(comment.id, 1, 20),
    enabled: showReplies && !comment.replies,
  });

  const replies = comment.replies || repliesData?.replies || [];
  const canReply = depth < MAX_DEPTH;
  const canEdit = user?.id === comment.user_id;
  const canDelete = user?.id === comment.user_id || user?.role === 'admin';

  // Create reply mutation
  // Action 4.4.1.5: Add optimistic update
  const createReplyMutation = useMutation({
    mutationFn: (content: string) =>
      createComment(trackId, content, comment.id),
    onMutate: async (content: string) => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({
        queryKey: ['commentReplies', comment.id],
      });
      await queryClient.cancelQueries({ queryKey: ['trackComments', trackId] });

      // Snapshot previous values
      const previousReplies = queryClient.getQueryData<ReplyListResponse>([
        'commentReplies',
        comment.id,
      ]);
      const previousComments = queryClient.getQueryData<CommentListResponse>([
        'trackComments',
        trackId,
      ]);

      // Optimistically add reply
      if (previousReplies && user) {
        const optimisticReply: TrackComment = {
          id: `temp-${Date.now()}`,
          track_id: trackId,
          user_id: user.id,
          parent_id: comment.id,
          content: content.trim(),
          is_edited: false,
          created_at: new Date().toISOString(),
          updated_at: new Date().toISOString(),
          user: {
            id: user.id,
            username: user.username || '',
            avatar: user.avatar_url,
          },
        };

        queryClient.setQueryData<ReplyListResponse>(
          ['commentReplies', comment.id],
          {
            ...previousReplies,
            replies: [...(previousReplies.replies || []), optimisticReply],
          },
        );
      }

      return { previousReplies, previousComments };
    },
    onError: (error: any, _content, context) => {
      // Rollback on error
      if (context?.previousReplies) {
        queryClient.setQueryData(
          ['commentReplies', comment.id],
          context.previousReplies,
        );
      }
      if (context?.previousComments) {
        queryClient.setQueryData(
          ['trackComments', trackId],
          context.previousComments,
        );
      }
      showError(error.message || 'Erreur lors de la publication de la réponse');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['trackComments', trackId] });
      queryClient.invalidateQueries({
        queryKey: ['commentReplies', comment.id],
      });
      setReplyContent('');
      setIsReplying(false);
      setShowReplies(true);
      showSuccess('Réponse publiée');
    },
  });

  // Update comment mutation
  // Action 4.4.1.5: Add optimistic update
  const updateCommentMutation = useMutation({
    mutationFn: (content: string) => updateComment(comment.id, content),
    onMutate: async (content: string) => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: ['trackComments', trackId] });
      await queryClient.cancelQueries({
        queryKey: ['commentReplies', comment.parent_id || comment.id],
      });

      // Snapshot previous values
      const previousComments = queryClient.getQueryData<CommentListResponse>([
        'trackComments',
        trackId,
      ]);
      const previousReplies = comment.parent_id
        ? queryClient.getQueryData<ReplyListResponse>([
            'commentReplies',
            comment.parent_id,
          ])
        : null;

      // Optimistically update comment in comments list
      if (previousComments) {
        queryClient.setQueryData<CommentListResponse>(
          ['trackComments', trackId],
          {
            ...previousComments,
            comments: previousComments.comments.map((c) =>
              c.id === comment.id
                ? {
                    ...c,
                    content: content.trim(),
                    is_edited: true,
                    updated_at: new Date().toISOString(),
                  }
                : c,
            ),
          },
        );
      }

      // Optimistically update reply in replies list
      if (previousReplies && comment.parent_id) {
        queryClient.setQueryData<ReplyListResponse>(
          ['commentReplies', comment.parent_id],
          {
            ...previousReplies,
            replies: previousReplies.replies.map((r) =>
              r.id === comment.id
                ? {
                    ...r,
                    content: content.trim(),
                    is_edited: true,
                    updated_at: new Date().toISOString(),
                  }
                : r,
            ),
          },
        );
      }

      return { previousComments, previousReplies };
    },
    onError: (error: any, _content, context) => {
      // Rollback on error
      if (context?.previousComments) {
        queryClient.setQueryData(
          ['trackComments', trackId],
          context.previousComments,
        );
      }
      if (context?.previousReplies && comment.parent_id) {
        queryClient.setQueryData(
          ['commentReplies', comment.parent_id],
          context.previousReplies,
        );
      }
      showError(error.message || 'Erreur lors de la modification');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['trackComments', trackId] });
      setIsEditing(false);
      showSuccess('Commentaire modifié');
    },
  });

  // Delete comment mutation
  // Action 4.4.1.5: Add optimistic update
  const deleteCommentMutation = useMutation({
    mutationFn: () => deleteComment(comment.id),
    onMutate: async () => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: ['trackComments', trackId] });
      await queryClient.cancelQueries({
        queryKey: ['commentReplies', comment.parent_id || comment.id],
      });

      // Snapshot previous values
      const previousComments = queryClient.getQueryData<CommentListResponse>([
        'trackComments',
        trackId,
      ]);
      const previousReplies = comment.parent_id
        ? queryClient.getQueryData<ReplyListResponse>([
            'commentReplies',
            comment.parent_id,
          ])
        : null;

      // Optimistically remove comment from comments list
      if (previousComments) {
        queryClient.setQueryData<CommentListResponse>(
          ['trackComments', trackId],
          {
            ...previousComments,
            comments: previousComments.comments.filter(
              (c) => c.id !== comment.id,
            ),
            total: Math.max((previousComments.total || 1) - 1, 0),
          },
        );
      }

      // Optimistically remove reply from replies list
      if (previousReplies && comment.parent_id) {
        queryClient.setQueryData<ReplyListResponse>(
          ['commentReplies', comment.parent_id],
          {
            ...previousReplies,
            replies: previousReplies.replies.filter((r) => r.id !== comment.id),
          },
        );
      }

      return { previousComments, previousReplies };
    },
    onError: (_error, _variables, context) => {
      // Rollback on error
      if (context?.previousComments) {
        queryClient.setQueryData(
          ['trackComments', trackId],
          context.previousComments,
        );
      }
      if (context?.previousReplies && comment.parent_id) {
        queryClient.setQueryData(
          ['commentReplies', comment.parent_id],
          context.previousReplies,
        );
      }
      showError('Erreur lors de la suppression');
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['trackComments', trackId] });
      setShowDeleteDialog(false);
      showSuccess('Commentaire supprimé');
    },
  });

  const handleReplySubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!replyContent.trim() || !user) return;
    createReplyMutation.mutate(replyContent.trim());
  };

  const handleEditSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!editContent.trim()) return;
    updateCommentMutation.mutate(editContent.trim());
  };

  const handleDelete = () => {
    deleteCommentMutation.mutate();
  };

  return (
    <>
      <div className={cn('space-y-3', className)}>
        {/* Main Comment */}
        <div className="flex gap-3">
          <Avatar
            src={comment.user?.avatar}
            fallback={comment.user?.username?.charAt(0).toUpperCase() || 'U'}
            size="sm"
            className="h-8 w-8 shrink-0"
          />
          <div className="flex-1 min-w-0 space-y-2">
            {/* Comment Header */}
            <div className="flex items-start justify-between gap-2">
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2 flex-wrap">
                  <span className="font-medium text-sm">
                    {comment.user?.username || 'Utilisateur'}
                  </span>
                  <span className="text-xs text-muted-foreground">
                    {formatDistanceToNow(new Date(comment.created_at), {
                      addSuffix: true,
                      locale: fr,
                    })}
                  </span>
                  {comment.is_edited && (
                    <span className="text-xs text-muted-foreground italic">
                      (modifié)
                    </span>
                  )}
                </div>
              </div>
              {(canEdit || canDelete) && (
                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button variant="ghost" size="icon" className="h-6 w-6">
                      <MoreVertical className="h-4 w-4" />
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="end">
                    {canEdit && (
                      <DropdownMenuItem onClick={() => setIsEditing(true)}>
                        <Edit2 className="mr-2 h-4 w-4" />
                        Modifier
                      </DropdownMenuItem>
                    )}
                    {canDelete && (
                      <DropdownMenuItem
                        onClick={() => setShowDeleteDialog(true)}
                        className="text-destructive"
                      >
                        <Trash2 className="mr-2 h-4 w-4" />
                        Supprimer
                      </DropdownMenuItem>
                    )}
                  </DropdownMenuContent>
                </DropdownMenu>
              )}
            </div>

            {/* Comment Content */}
            {isEditing ? (
              <form onSubmit={handleEditSubmit} className="space-y-2">
                <Input
                  value={editContent}
                  onChange={(e) => setEditContent(e.target.value)}
                  maxLength={500}
                  autoFocus
                />
                <div className="flex gap-2">
                  <Button
                    type="submit"
                    size="sm"
                    disabled={
                      !editContent.trim() || updateCommentMutation.isPending
                    }
                  >
                    {updateCommentMutation.isPending ? (
                      <Loader2 className="h-4 w-4 mr-2 animate-spin" />
                    ) : (
                      <Send className="h-4 w-4 mr-2" />
                    )}
                    Enregistrer
                  </Button>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => {
                      setIsEditing(false);
                      setEditContent(comment.content);
                    }}
                  >
                    <X className="h-4 w-4 mr-2" />
                    Annuler
                  </Button>
                </div>
              </form>
            ) : (
              <p className="text-sm whitespace-pre-wrap break-words">
                {comment.content}
              </p>
            )}

            {/* Comment Actions */}
            {!isEditing && (
              <div className="flex items-center gap-4">
                {canReply && user && (
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => setIsReplying(!isReplying)}
                    className="h-7 text-xs"
                  >
                    <Reply className="h-3 w-3 mr-1" />
                    Répondre
                  </Button>
                )}
                {replies.length > 0 && (
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => setShowReplies(!showReplies)}
                    className="h-7 text-xs"
                  >
                    <MessageCircle className="h-3 w-3 mr-1" />
                    {showReplies ? 'Masquer' : 'Afficher'} {replies.length}{' '}
                    {replies.length === 1 ? 'réponse' : 'réponses'}
                  </Button>
                )}
              </div>
            )}

            {/* Reply Form */}
            {isReplying && user && (
              <form onSubmit={handleReplySubmit} className="space-y-2 pt-2">
                <Input
                  value={replyContent}
                  onChange={(e) => setReplyContent(e.target.value)}
                  placeholder={`Répondre à ${comment.user?.username}...`}
                  maxLength={500}
                  autoFocus
                />
                <div className="flex gap-2">
                  <Button
                    type="submit"
                    size="sm"
                    disabled={
                      !replyContent.trim() || createReplyMutation.isPending
                    }
                  >
                    {createReplyMutation.isPending ? (
                      <Loader2 className="h-4 w-4 mr-2 animate-spin" />
                    ) : (
                      <Send className="h-4 w-4 mr-2" />
                    )}
                    Publier
                  </Button>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => {
                      setIsReplying(false);
                      setReplyContent('');
                    }}
                  >
                    <X className="h-4 w-4 mr-2" />
                    Annuler
                  </Button>
                </div>
              </form>
            )}

            {/* Replies */}
            {showReplies && (
              <div className="space-y-3 pt-2 pl-4 border-l-2 border-muted">
                {isLoadingReplies ? (
                  <div className="flex items-center justify-center py-4">
                    <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
                  </div>
                ) : replies.length > 0 ? (
                  replies.map((reply) => (
                    <CommentThread
                      key={reply.id}
                      comment={reply}
                      trackId={trackId}
                      depth={depth + 1}
                    />
                  ))
                ) : null}
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Delete Confirmation Dialog */}
      <ConfirmationDialog
        open={showDeleteDialog}
        onClose={() => setShowDeleteDialog(false)}
        onConfirm={handleDelete}
        title="Supprimer le commentaire"
        description="Êtes-vous sûr de vouloir supprimer ce commentaire ? Cette action est irréversible."
        confirmLabel="Supprimer"
        cancelLabel="Annuler"
        variant="destructive"
      />
    </>
  );
}
