import { describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SignInForm } from './SignInForm';
import type { SignInModalState, SignInModalActions } from './types';

function createMockState(overrides: Partial<SignInModalState> = {}): SignInModalState {
  return {
    mode: 'signin',
    signupStep: 1,
    draft: {
      email: '',
      password: '',
      confirmPassword: '',
      fullName: '',
      role: 'teacher',
      campus: '',
      showPassword: false,
    },
    loading: false,
    error: null,
    success: null,
    selectedCampusId: '',
    campuses: [],
    campusesLoading: false,
    campusesError: null,
    ...overrides,
  };
}

function createMockActions(overrides: Partial<SignInModalActions> = {}): SignInModalActions {
  return {
    updateDraft: vi.fn(),
    setRole: vi.fn(),
    setCampus: vi.fn(),
    setShowPassword: vi.fn(),
    handleSignIn: vi.fn().mockResolvedValue(undefined),
    goToNextStep: vi.fn(),
    goToPreviousStep: vi.fn(),
    handleClose: vi.fn(),
    switchMode: vi.fn(),
    getNextSignupStep: vi.fn(),
    ...overrides,
  };
}

describe('SignInForm', () => {
  it('renders email and password fields', () => {
    const state = createMockState();
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByPlaceholderText(/you@school\.edu/i)).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/enter your password/i)).toBeInTheDocument();
  });

  it('renders sign in button', () => {
    const state = createMockState();
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

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

  it('disables submit button when loading', () => {
    const state = createMockState({ loading: true });
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByRole('button', { name: /signing in/i })).toBeDisabled();
  });

  it('shows loading text when loading', () => {
    const state = createMockState({ loading: true });
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByText(/signing in/i)).toBeInTheDocument();
  });

  it('calls handleSignIn on form submit', async () => {
    const user = userEvent.setup();
    const state = createMockState({
      draft: {
        email: 'test@example.com',
        password: 'password123',
        confirmPassword: '',
        fullName: '',
        role: 'teacher',
        campus: '',
        showPassword: false,
      },
    });
    const handleSignIn = vi.fn().mockResolvedValue(undefined);
    const actions = createMockActions({ handleSignIn });

    render(<SignInForm state={state} actions={actions} />);

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

    expect(handleSignIn).toHaveBeenCalledTimes(1);
  });

  it('calls updateDraft when email input changes', async () => {
    const user = userEvent.setup();
    const state = createMockState();
    const updateDraft = vi.fn();
    const actions = createMockActions({ updateDraft });

    render(<SignInForm state={state} actions={actions} />);

    const emailInput = screen.getByPlaceholderText(/you@school\.edu/i);
    await user.type(emailInput, 'new@example.com');

    expect(updateDraft).toHaveBeenCalled();
    expect(updateDraft).toHaveBeenCalledWith(expect.objectContaining({ email: expect.any(String) }));
  });

  it('calls updateDraft when password input changes', async () => {
    const user = userEvent.setup();
    const state = createMockState();
    const updateDraft = vi.fn();
    const actions = createMockActions({ updateDraft });

    render(<SignInForm state={state} actions={actions} />);

    const passwordInput = screen.getByPlaceholderText(/enter your password/i);
    await user.type(passwordInput, 'secret');

    expect(updateDraft).toHaveBeenCalled();
    expect(updateDraft).toHaveBeenCalledWith(expect.objectContaining({ password: expect.any(String) }));
  });

  it('toggles password visibility when toggle button is clicked', async () => {
    const user = userEvent.setup();
    const state = createMockState();
    const setShowPassword = vi.fn();
    const actions = createMockActions({ setShowPassword });

    render(<SignInForm state={state} actions={actions} />);

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

    expect(setShowPassword).toHaveBeenCalledWith(true);
  });

  it('shows hide password button when password is visible', async () => {
    const user = userEvent.setup();
    const state = createMockState({
      draft: {
        email: '',
        password: '',
        confirmPassword: '',
        fullName: '',
        role: 'teacher',
        campus: '',
        showPassword: true,
      },
    });
    const setShowPassword = vi.fn();
    const actions = createMockActions({ setShowPassword });

    render(<SignInForm state={state} actions={actions} />);

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

    expect(setShowPassword).toHaveBeenCalledWith(false);
  });

  it('displays current email value from state', () => {
    const state = createMockState({
      draft: {
        email: 'existing@example.com',
        password: '',
        confirmPassword: '',
        fullName: '',
        role: 'teacher',
        campus: '',
        showPassword: false,
      },
    });
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByPlaceholderText(/you@school\.edu/i)).toHaveValue('existing@example.com');
  });

  it('displays current password value from state', () => {
    const state = createMockState({
      draft: {
        email: '',
        password: 'currentpass',
        confirmPassword: '',
        fullName: '',
        role: 'teacher',
        campus: '',
        showPassword: false,
      },
    });
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByPlaceholderText(/enter your password/i)).toHaveValue('currentpass');
  });

  it('has required attribute on email field', () => {
    const state = createMockState();
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByPlaceholderText(/you@school\.edu/i)).toBeRequired();
  });

  it('has required attribute on password field', () => {
    const state = createMockState();
    const actions = createMockActions();

    render(<SignInForm state={state} actions={actions} />);

    expect(screen.getByPlaceholderText(/enter your password/i)).toBeRequired();
  });
});
