/**
 * ProjectWizard Component Tests
 *
 * Tests for the main project creation wizard component.
 */

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ProjectWizard } from '@/components/projects/wizard/ProjectWizard';

// Mock step components
jest.mock('@/components/projects/wizard/steps', () => ({
  BasicInfoStep: jest.fn(({ updateState }) => (
    <div data-testid="basic-info-step">
      <button onClick={() => updateState({ projectName: 'Test Project' })}>Set Name</button>
    </div>
  )),
  ComplexityStep: jest.fn(({ updateState }) => (
    <div data-testid="complexity-step">
      <button onClick={() => updateState({ complexity: 'simple' })}>Set Simple</button>
      <button onClick={() => updateState({ complexity: 'script' })}>Set Script</button>
    </div>
  )),
  ClientModeStep: jest.fn(() => <div data-testid="client-mode-step" />),
  AutonomyStep: jest.fn(() => <div data-testid="autonomy-step" />),
  AgentChatStep: jest.fn(() => <div data-testid="agent-chat-step" />),
  ReviewStep: jest.fn(({ state }) => (
    <div data-testid="review-step">
      <span>Project: {state.projectName}</span>
    </div>
  )),
}));

// Mock StepIndicator
jest.mock('@/components/projects/wizard/StepIndicator', () => ({
  StepIndicator: jest.fn(({ currentStep, isScriptMode }) => (
    <div data-testid="step-indicator">
      Step {currentStep} {isScriptMode && '(script mode)'}
    </div>
  )),
}));

// Mock useWizardState hook
const mockUpdateState = jest.fn();
const mockResetState = jest.fn();
const mockGoNext = jest.fn();
const mockGoBack = jest.fn();
const mockGetProjectData = jest.fn(() => ({
  name: 'Test Project',
  slug: 'test-project',
  description: 'Test description',
  autonomy_level: 'milestone',
  settings: {},
}));

let mockWizardState = {
  step: 1 as 1 | 2 | 3 | 4 | 5 | 6,
  projectName: 'Test Project',
  description: '',
  repoUrl: '',
  complexity: null as string | null,
  clientMode: null as string | null,
  autonomyLevel: null as string | null,
};

jest.mock('@/components/projects/wizard/useWizardState', () => ({
  useWizardState: jest.fn(() => ({
    state: mockWizardState,
    updateState: mockUpdateState,
    resetState: mockResetState,
    isScriptMode: mockWizardState.complexity === 'script',
    canProceed: mockWizardState.projectName.length > 0,
    goNext: mockGoNext,
    goBack: mockGoBack,
    getProjectData: mockGetProjectData,
  })),
}));

// Mock router
const mockPush = jest.fn();
jest.mock('next/navigation', () => ({
  useRouter: () => ({
    push: mockPush,
  }),
}));

// Mock API client
const mockPost = jest.fn();
jest.mock('@/lib/api/client', () => ({
  apiClient: {
    instance: {
      post: jest.fn((url, data) => mockPost(url, data)),
    },
  },
}));

function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
}

describe('ProjectWizard', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockWizardState = {
      step: 1,
      projectName: 'Test Project',
      description: '',
      repoUrl: '',
      complexity: null,
      clientMode: null,
      autonomyLevel: null,
    };
    mockPost.mockResolvedValue({
      data: {
        id: 'project-123',
        name: 'Test Project',
        slug: 'test-project',
      },
    });
  });

  describe('Rendering', () => {
    it('renders the step indicator', () => {
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByTestId('step-indicator')).toBeInTheDocument();
    });

    it('renders BasicInfoStep on step 1', () => {
      mockWizardState.step = 1;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByTestId('basic-info-step')).toBeInTheDocument();
    });

    it('renders ComplexityStep on step 2', () => {
      mockWizardState.step = 2;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByTestId('complexity-step')).toBeInTheDocument();
    });

    it('renders AgentChatStep on step 5', () => {
      mockWizardState.step = 5;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByTestId('agent-chat-step')).toBeInTheDocument();
    });

    it('renders ReviewStep on step 6', () => {
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByTestId('review-step')).toBeInTheDocument();
    });

    it('applies custom className', () => {
      const { container } = render(<ProjectWizard locale="en" className="custom-class" />, {
        wrapper: createWrapper(),
      });
      expect(container.firstChild).toHaveClass('custom-class');
    });
  });

  describe('Navigation', () => {
    it('calls goNext when Next button is clicked', async () => {
      const user = userEvent.setup();
      mockWizardState.step = 1;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /next/i }));
      expect(mockGoNext).toHaveBeenCalled();
    });

    it('calls goBack when Back button is clicked', async () => {
      const user = userEvent.setup();
      mockWizardState.step = 2;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /back/i }));
      expect(mockGoBack).toHaveBeenCalled();
    });

    it('hides Back button on step 1', () => {
      mockWizardState.step = 1;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      const backButton = screen.getByRole('button', { name: /back/i });
      expect(backButton).toHaveClass('invisible');
    });

    it('shows Back button visible on step 2', () => {
      mockWizardState.step = 2;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      const backButton = screen.getByRole('button', { name: /back/i });
      expect(backButton).not.toHaveClass('invisible');
    });

    it('shows Create Project button on review step', () => {
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByRole('button', { name: /create project/i })).toBeInTheDocument();
    });
  });

  describe('Script Mode', () => {
    it('skips client mode step in script mode', () => {
      mockWizardState.step = 3;
      mockWizardState.complexity = 'script';
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      // ClientModeStep should not render for script mode
      expect(screen.queryByTestId('client-mode-step')).not.toBeInTheDocument();
    });

    it('skips autonomy step in script mode', () => {
      mockWizardState.step = 4;
      mockWizardState.complexity = 'script';
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      // AutonomyStep should not render for script mode
      expect(screen.queryByTestId('autonomy-step')).not.toBeInTheDocument();
    });

    it('shows script mode indicator', () => {
      mockWizardState.complexity = 'script';
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByText(/script mode/i)).toBeInTheDocument();
    });
  });

  describe('Project Creation', () => {
    it('shows success screen after creation', async () => {
      const user = userEvent.setup();
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /create project/i }));

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

    it('displays project name in success message', async () => {
      const user = userEvent.setup();
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /create project/i }));

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

    it('navigates to project dashboard on success', async () => {
      const user = userEvent.setup();
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /create project/i }));

      await waitFor(() => {
        expect(
          screen.getByRole('button', { name: /go to project dashboard/i })
        ).toBeInTheDocument();
      });

      await user.click(screen.getByRole('button', { name: /go to project dashboard/i }));
      expect(mockPush).toHaveBeenCalledWith('/en/projects/test-project');
    });

    it('allows creating another project', async () => {
      const user = userEvent.setup();
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /create project/i }));

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /create another project/i })).toBeInTheDocument();
      });

      await user.click(screen.getByRole('button', { name: /create another project/i }));
      expect(mockResetState).toHaveBeenCalled();
    });
  });

  describe('Error Handling', () => {
    it('shows error message on creation failure', async () => {
      mockPost.mockRejectedValue(new Error('Network error'));
      const user = userEvent.setup();
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /create project/i }));

      await waitFor(() => {
        expect(screen.getByText(/failed to create project/i)).toBeInTheDocument();
      });
    });
  });

  describe('Button States', () => {
    it('disables Next button when cannot proceed', () => {
      mockWizardState.projectName = '';
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByRole('button', { name: /next/i })).toBeDisabled();
    });

    it('enables Next button when can proceed', () => {
      mockWizardState.projectName = 'Valid Name';
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });
      expect(screen.getByRole('button', { name: /next/i })).not.toBeDisabled();
    });

    it('shows loading state during creation', async () => {
      mockPost.mockImplementation(
        () => new Promise((resolve) => setTimeout(() => resolve({ data: {} }), 1000))
      );
      const user = userEvent.setup();
      mockWizardState.step = 6;
      render(<ProjectWizard locale="en" />, { wrapper: createWrapper() });

      await user.click(screen.getByRole('button', { name: /create project/i }));
      expect(screen.getByText(/creating/i)).toBeInTheDocument();
    });
  });
});
