import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CommentItem } from './CommentItem';
import {
  updateComment,
  deleteComment,
  getReplies,
} from '../services/commentService';
import { useAuthStore } from '@/features/auth/store/authStore';
import { useToast } from '@/hooks/useToast';
import type { TrackComment } from '../services/commentService';

// Mock dependencies
vi.mock('../services/commentService');
vi.mock('@/features/auth/store/authStore');
vi.mock('@/hooks/useToast');

describe('CommentItem', () => {
  const mockToast = {
    success: vi.fn(),
    error: vi.fn(),
    warning: vi.fn(),
    info: vi.fn(),
    toast: vi.fn(),
  };

  const mockUser = {
    id: 123,
    username: 'testuser',
    email: 'test@example.com',
  };

  const mockComment: TrackComment = {
    id: 1,
    track_id: 1,
    creator_id: 123,
    content: 'Great track!',
    is_edited: false,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
    user: {
      id: 123,
      username: 'testuser',
    },
  };

  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(useAuthStore).mockReturnValue({
      user: mockUser,
      isAuthenticated: true,
      isLoading: false,
      error: null,
      login: vi.fn(),
      register: vi.fn(),
      logout: vi.fn(),
      refreshUser: vi.fn(),
      clearError: vi.fn(),
      setLoading: vi.fn(),
      checkAuthStatus: vi.fn(),
    });
    vi.mocked(useToast).mockReturnValue(mockToast);
    // Mock window.confirm
    window.confirm = vi.fn(() => true);
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should render comment', () => {
    render(<CommentItem comment={mockComment} trackId={1} />);

    expect(screen.getByText('Great track!')).toBeInTheDocument();
    expect(screen.getByText('testuser')).toBeInTheDocument();
  });

  it('should show edit and delete buttons for owner', () => {
    render(<CommentItem comment={mockComment} trackId={1} />);

    expect(
      screen.getByRole('button', { name: /modifier/i }),
    ).toBeInTheDocument();
    expect(
      screen.getByRole('button', { name: /supprimer/i }),
    ).toBeInTheDocument();
  });

  it('should not show edit and delete buttons for non-owner', () => {
    const otherUser = {
      id: 456,
      username: 'otheruser',
      email: 'other@example.com',
    };
    vi.mocked(useAuthStore).mockReturnValue({
      user: otherUser,
      isAuthenticated: true,
      isLoading: false,
      error: null,
      login: vi.fn(),
      register: vi.fn(),
      logout: vi.fn(),
      refreshUser: vi.fn(),
      clearError: vi.fn(),
      setLoading: vi.fn(),
      checkAuthStatus: vi.fn(),
    });

    render(<CommentItem comment={mockComment} trackId={1} />);

    expect(
      screen.queryByRole('button', { name: /modifier/i }),
    ).not.toBeInTheDocument();
    expect(
      screen.queryByRole('button', { name: /supprimer/i }),
    ).not.toBeInTheDocument();
  });

  it('should show edit form when edit button is clicked', async () => {
    const user = userEvent.setup();
    render(<CommentItem comment={mockComment} trackId={1} />);

    const editButton = screen.getByRole('button', { name: /modifier/i });
    await user.click(editButton);

    await waitFor(() => {
      expect(
        screen.getByPlaceholderText('Modifier le commentaire...'),
      ).toBeInTheDocument();
    });
  });

  it('should update comment', async () => {
    const user = userEvent.setup();
    const updatedComment: TrackComment = {
      ...mockComment,
      content: 'Updated content',
      is_edited: true,
    };
    vi.mocked(updateComment).mockResolvedValue(updatedComment);

    render(<CommentItem comment={mockComment} trackId={1} />);

    const editButton = screen.getByRole('button', { name: /modifier/i });
    await user.click(editButton);

    await waitFor(() => {
      expect(
        screen.getByPlaceholderText('Modifier le commentaire...'),
      ).toBeInTheDocument();
    });

    const textarea = screen.getByPlaceholderText('Modifier le commentaire...');
    await user.clear(textarea);
    await user.type(textarea, 'Updated content');

    const submitButton = screen.getByRole('button', { name: /commenter/i });
    await user.click(submitButton);

    await waitFor(() => {
      expect(updateComment).toHaveBeenCalledWith(1, 'Updated content');
      expect(mockToast.success).toHaveBeenCalledWith('Commentaire mis à jour');
    });
  });

  it('should delete comment', async () => {
    const user = userEvent.setup();
    vi.mocked(deleteComment).mockResolvedValue(undefined);

    render(<CommentItem comment={mockComment} trackId={1} />);

    const deleteButton = screen.getByRole('button', { name: /supprimer/i });
    await user.click(deleteButton);

    await waitFor(() => {
      expect(window.confirm).toHaveBeenCalled();
      expect(deleteComment).toHaveBeenCalledWith(1);
      expect(mockToast.success).toHaveBeenCalledWith('Commentaire supprimé');
    });
  });

  it('should show reply form when reply button is clicked', async () => {
    const user = userEvent.setup();
    render(<CommentItem comment={mockComment} trackId={1} />);

    const replyButton = screen.getByRole('button', { name: /répondre/i });
    await user.click(replyButton);

    await waitFor(() => {
      expect(
        screen.getByPlaceholderText('Écrivez une réponse...'),
      ).toBeInTheDocument();
    });
  });

  it('should display replies', async () => {
    const commentWithReplies: TrackComment = {
      ...mockComment,
      replies: [
        {
          id: 2,
          track_id: 1,
          creator_id: 456,
          parent_id: 1,
          content: 'Reply 1',
          is_edited: false,
          created_at: '2024-01-02T00:00:00Z',
          updated_at: '2024-01-02T00:00:00Z',
          user: {
            id: 456,
            username: 'otheruser',
          },
        },
      ],
    };

    render(<CommentItem comment={commentWithReplies} trackId={1} />);

    await waitFor(() => {
      expect(screen.getByText(/afficher.*réponse/i)).toBeInTheDocument();
    });
  });

  it('should show edited indicator', () => {
    const editedComment: TrackComment = {
      ...mockComment,
      is_edited: true,
    };

    render(<CommentItem comment={editedComment} trackId={1} />);

    expect(screen.getByText('(modifié)')).toBeInTheDocument();
  });
});
