import { render, screen, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { BrowserRouter, MemoryRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { UserProfilePage } from './UserProfilePage';
import * as profileService from '../services/profileService';

// Mock ResizeObserver for tests
global.ResizeObserver = vi.fn().mockImplementation(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

// Mock profileService
vi.mock('../services/profileService', () => ({
  getProfileByUsername: vi.fn(),
}));

const createTestQueryClient = () =>
  new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

const TestWrapper = ({
  children,
  initialEntries = ['/u/testuser'],
}: {
  children: React.ReactNode;
  initialEntries?: string[];
}) => {
  const queryClient = createTestQueryClient();
  return (
    <QueryClientProvider client={queryClient}>
      <MemoryRouter initialEntries={initialEntries}>{children}</MemoryRouter>
    </QueryClientProvider>
  );
};

describe('UserProfilePage Component', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders loading state initially', () => {
    vi.mocked(profileService.getProfileByUsername).mockImplementation(
      () => new Promise(() => {}), // Never resolves
    );

    render(
      <TestWrapper>
        <UserProfilePage />
      </TestWrapper>,
    );

    expect(screen.getByText(/loading profile/i)).toBeInTheDocument();
  });

  it('renders profile successfully', async () => {
    const mockProfile = {
      id: 123,
      username: 'testuser',
      first_name: 'Test',
      last_name: 'User',
      avatar_url: 'https://example.com/avatar.jpg',
      bio: 'Test bio',
      location: 'Paris',
      birthdate: null,
      gender: null,
      created_at: '2024-01-01T00:00:00Z',
    };

    vi.mocked(profileService.getProfileByUsername).mockResolvedValue(
      mockProfile,
    );

    render(
      <TestWrapper>
        <UserProfilePage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText('testuser')).toBeInTheDocument();
    });

    expect(screen.getByText('Test User')).toBeInTheDocument();
    expect(screen.getByText('Test bio')).toBeInTheDocument();
    expect(screen.getByText(/Paris/i)).toBeInTheDocument();
  });

  it('displays error message when profile fails to load', async () => {
    vi.mocked(profileService.getProfileByUsername).mockRejectedValue(
      new Error('User not found'),
    );

    render(
      <TestWrapper>
        <UserProfilePage />
      </TestWrapper>,
    );

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

  it('displays error when username is missing', async () => {
    render(
      <TestWrapper initialEntries={['/u/']}>
        <UserProfilePage />
      </TestWrapper>,
    );

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

  it('displays user not found when profile is null', async () => {
    vi.mocked(profileService.getProfileByUsername).mockResolvedValue(
      null as any,
    );

    render(
      <TestWrapper>
        <UserProfilePage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText(/user not found/i)).toBeInTheDocument();
    });
  });

  it('displays profile without optional fields', async () => {
    const mockProfile = {
      id: 123,
      username: 'testuser',
      first_name: null,
      last_name: null,
      avatar_url: null,
      bio: null,
      location: null,
      birthdate: null,
      gender: null,
      created_at: '2024-01-01T00:00:00Z',
    };

    vi.mocked(profileService.getProfileByUsername).mockResolvedValue(
      mockProfile,
    );

    render(
      <TestWrapper>
        <UserProfilePage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText('testuser')).toBeInTheDocument();
    });

    // Bio and location should not be displayed
    expect(screen.queryByText(/bio/i)).not.toBeInTheDocument();
    expect(screen.queryByText(/location/i)).not.toBeInTheDocument();
  });

  it('formats date correctly', async () => {
    const mockProfile = {
      id: 123,
      username: 'testuser',
      first_name: null,
      last_name: null,
      avatar_url: null,
      bio: null,
      location: null,
      birthdate: null,
      gender: null,
      created_at: '2024-01-15T00:00:00Z',
    };

    vi.mocked(profileService.getProfileByUsername).mockResolvedValue(
      mockProfile,
    );

    render(
      <TestWrapper>
        <UserProfilePage />
      </TestWrapper>,
    );

    await waitFor(() => {
      expect(screen.getByText(/member since/i)).toBeInTheDocument();
    });

    // Check that the date is formatted
    const dateText =
      screen.getByText(/member since/i).parentElement?.textContent;
    expect(dateText).toContain('1/15/2024');
  });
});
