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 { CommentForm } from './CommentForm';
import { useToast } from '@/hooks/useToast';

// Mock dependencies
vi.mock('@/hooks/useToast');

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

  const mockOnSubmit = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(useToast).mockReturnValue(mockToast);
  });

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

  it('should render comment form', () => {
    render(<CommentForm onSubmit={mockOnSubmit} />);

    expect(
      screen.getByPlaceholderText('Écrivez un commentaire...'),
    ).toBeInTheDocument();
    expect(
      screen.getByRole('button', { name: /commenter/i }),
    ).toBeInTheDocument();
  });

  it('should submit comment', async () => {
    const user = userEvent.setup();
    mockOnSubmit.mockResolvedValue(undefined);

    render(<CommentForm onSubmit={mockOnSubmit} />);

    const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
    await user.type(textarea, 'Test comment');

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

    await waitFor(() => {
      expect(mockOnSubmit).toHaveBeenCalledWith('Test comment', undefined);
    });
  });

  it('should submit reply comment', async () => {
    const user = userEvent.setup();
    mockOnSubmit.mockResolvedValue(undefined);

    render(<CommentForm onSubmit={mockOnSubmit} parentId={1} />);

    const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
    await user.type(textarea, 'Test reply');

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

    await waitFor(() => {
      expect(mockOnSubmit).toHaveBeenCalledWith('Test reply', 1);
    });
  });

  it('should show error for empty comment', async () => {
    const user = userEvent.setup();

    render(<CommentForm onSubmit={mockOnSubmit} />);

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

    await waitFor(() => {
      expect(mockToast.error).toHaveBeenCalledWith(
        'Le commentaire ne peut pas être vide',
      );
      expect(mockOnSubmit).not.toHaveBeenCalled();
    });
  });

  it('should show error for comment too long', async () => {
    const user = userEvent.setup();
    const longContent = 'a'.repeat(5001);

    render(<CommentForm onSubmit={mockOnSubmit} />);

    const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
    await user.type(textarea, longContent);

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

    await waitFor(() => {
      expect(mockToast.error).toHaveBeenCalledWith(
        'Le commentaire ne peut pas dépasser 5000 caractères',
      );
      expect(mockOnSubmit).not.toHaveBeenCalled();
    });
  });

  it('should display character count', async () => {
    const user = userEvent.setup();

    render(<CommentForm onSubmit={mockOnSubmit} />);

    const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
    await user.type(textarea, 'Test');

    expect(screen.getByText('4/5000')).toBeInTheDocument();
  });

  it('should call onCancel when cancel button is clicked', async () => {
    const user = userEvent.setup();
    const mockOnCancel = vi.fn();

    render(<CommentForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />);

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

    expect(mockOnCancel).toHaveBeenCalled();
  });

  it('should clear form after successful submit', async () => {
    const user = userEvent.setup();
    mockOnSubmit.mockResolvedValue(undefined);

    render(<CommentForm onSubmit={mockOnSubmit} />);

    const textarea = screen.getByPlaceholderText(
      'Écrivez un commentaire...',
    ) as HTMLTextAreaElement;
    await user.type(textarea, 'Test comment');

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

    await waitFor(() => {
      expect(textarea.value).toBe('');
    });
  });

  it('should show loading state during submit', async () => {
    const user = userEvent.setup();
    mockOnSubmit.mockImplementation(
      () =>
        new Promise((resolve) => {
          setTimeout(() => resolve(undefined), 100);
        }),
    );

    render(<CommentForm onSubmit={mockOnSubmit} />);

    const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
    await user.type(textarea, 'Test comment');

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

    await waitFor(() => {
      expect(screen.getByText(/envoi/i)).toBeInTheDocument();
      expect(submitButton).toBeDisabled();
    });
  });

  it('should handle submit error', async () => {
    const user = userEvent.setup();
    const error = new Error('Failed to create comment');
    mockOnSubmit.mockRejectedValue(error);

    render(<CommentForm onSubmit={mockOnSubmit} />);

    const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
    await user.type(textarea, 'Test comment');

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

    await waitFor(() => {
      expect(mockToast.error).toHaveBeenCalledWith('Failed to create comment');
    });
  });
});
