import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ThemeProvider } from '../../theme';

const mockVerifyMutate = jest.fn();
const mockVerifyReset = jest.fn();
const mockRequestMutate = jest.fn();

jest.mock('next-intl', () => ({
  useLocale: () => 'fa',
  useTranslations: () => {
    const t = (key: string) => key;
    t.rich = (key: string) => key;
    return t;
  },
}));
jest.mock('@/services/auth', () => ({
  useVerifyOtp: () => ({ isPending: false, isError: false, mutate: mockVerifyMutate, reset: mockVerifyReset }),
  useRequestOtp: () => ({ isPending: false, mutate: mockRequestMutate }),
}));

import OtpStep from './OtpStep';

const PHONE = '09120001234';

function renderStep() {
  const onVerified = jest.fn();
  const onChangeNumber = jest.fn();
  render(
    <ThemeProvider>
      <OtpStep
        phone={PHONE}
        intendedRole="customer"
        resendSeconds={120}
        onVerified={onVerified}
        onChangeNumber={onChangeNumber}
      />
    </ThemeProvider>,
  );
  return { onVerified, onChangeNumber };
}

async function fillCode(code: string) {
  const user = userEvent.setup();
  const boxes = screen.getAllByRole('textbox') as HTMLInputElement[];
  for (let i = 0; i < code.length; i += 1) {
    await user.type(boxes[i], code[i]);
  }
}

describe('<OtpStep/> state machine', () => {
  beforeEach(() => {
    mockVerifyMutate.mockReset();
    mockVerifyReset.mockReset();
    mockRequestMutate.mockReset();
  });

  it('renders one box per code digit (6)', () => {
    renderStep();
    expect(screen.getAllByRole('textbox')).toHaveLength(6);
  });

  it('auto-verifies once the last box is filled', async () => {
    renderStep();
    await fillCode('123456');
    expect(mockVerifyMutate).toHaveBeenCalledWith(
      { phone: PHONE, code: '123456' },
      expect.any(Object),
    );
  });

  it('calls onVerified on a successful verify', async () => {
    mockVerifyMutate.mockImplementation((_vars, opts) => opts.onSuccess?.());
    const { onVerified } = renderStep();
    await fillCode('123456');
    expect(onVerified).toHaveBeenCalledTimes(1);
  });

  it('clears the boxes on a wrong code so the user can retry', async () => {
    mockVerifyMutate.mockImplementation((_vars, opts) => opts.onError?.(new Error('bad code')));
    renderStep();
    await fillCode('000000');
    const boxes = screen.getAllByRole('textbox') as HTMLInputElement[];
    expect(boxes.every((box) => box.value === '')).toBe(true);
  });
});
