import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter } from 'react-router-dom';
import SignUp from './SignUp';
import { AuthContext } from '../../contexts/AuthContext';
import { AccountContext } from '../../contexts/AccountContext';

jest.mock('../../components/ParticleBackground/ParticleBackground', () => () => null);

jest.mock('../../utils/revenueCat', () => ({
  logInRevenueCat: () => Promise.resolve(),
  purchasePlan: () => Promise.resolve(),
}));

const mockPost = jest.fn();
const mockGet = jest.fn();
const assignMock = jest.fn();

jest.mock('../../../axiosApi', () => ({
  axiosInstance: {
    post: (...args: unknown[]) => mockPost(...args),
    get: (...args: unknown[]) => mockGet(...args),
    defaults: { headers: { common: {} as Record<string, string | null> } },
  },
  applyAccessToken: jest.fn(),
}));

const renderSignUp = () => {
  const setAuthentication = jest.fn();
  const setNeedsNewPassword = jest.fn();
  const setAccount = jest.fn();

  render(
    <MemoryRouter>
      <AuthContext.Provider
        value={{
          authenticated: false,
          setAuthentication,
          needsNewPassword: false,
          setNeedsNewPassword,
          loading: false,
        }}
      >
        <AccountContext.Provider value={{ account: undefined, setAccount }}>
          <SignUp />
        </AccountContext.Provider>
      </AuthContext.Provider>
    </MemoryRouter>
  );

  return { setAuthentication, setNeedsNewPassword, setAccount };
};

describe('SignUp', () => {
  const originalLocation = window.location;

  beforeEach(() => {
    localStorage.clear();
    mockPost.mockReset();
    mockGet.mockReset();
    assignMock.mockReset();
    Object.defineProperty(window, 'location', {
      configurable: true,
      value: { ...originalLocation, assign: assignMock, origin: 'http://localhost' },
    });
  });

  afterEach(() => {
    Object.defineProperty(window, 'location', {
      configurable: true,
      value: originalLocation,
    });
  });

  it('shows disabled message when registration flag is off', async () => {
    mockGet.mockResolvedValue({ data: { enable_account_registration: false } });
    renderSignUp();

    expect(await screen.findByText(/not available right now/i)).toBeInTheDocument();
    expect(screen.queryByPlaceholderText('Email Address')).not.toBeInTheDocument();
  });

  it('does not submit when required fields empty', async () => {
    mockGet.mockResolvedValue({ data: { enable_account_registration: true } });
    const user = userEvent.setup();
    renderSignUp();

    expect(await screen.findByPlaceholderText('Email Address')).toBeInTheDocument();
    await user.click(screen.getByRole('button', { name: /Sign Up & Pay/i }));

    await waitFor(() => {
      expect(mockPost).not.toHaveBeenCalled();
    });
  });

  it('registers then redirects to Stripe Checkout URL', async () => {
    mockGet
      .mockResolvedValueOnce({ data: { enable_account_registration: true } })
      .mockResolvedValueOnce({
        data: {
          email: 'new@example.com',
          first_name: 'New',
          last_name: 'User',
          is_company_manager: true,
          has_signed_tos: false,
          has_usable_password: true,
          company: { id: 1, name: 'New Co', state: 'NA', zipcode: '00000', address: 'N/A' },
        },
      });
    mockPost
      .mockResolvedValueOnce({
        data: { access: 'access-token', refresh: 'refresh-token', email: 'new@example.com' },
      })
      .mockResolvedValueOnce({
        data: {
          checkout_url: 'https://checkout.stripe.com/c/pay/cs_test_abc',
          session_id: 'cs_test_abc',
        },
      });

    const user = userEvent.setup();
    const { setAuthentication } = renderSignUp();

    await screen.findByPlaceholderText('Email Address');
    await user.type(screen.getByPlaceholderText('Email Address'), 'new@example.com');
    await user.type(screen.getByPlaceholderText('Password'), 'securepass1');
    await user.type(screen.getByPlaceholderText('Confirm password'), 'securepass1');
    await user.click(screen.getByRole('button', { name: /Sign Up & Pay/i }));

    await waitFor(() => {
      expect(mockPost).toHaveBeenCalledWith('/user/create/', {
        email: 'new@example.com',
        password: 'securepass1',
        first_name: '',
        last_name: '',
        company_name: '',
      });
    });

    await waitFor(() => {
      expect(mockPost).toHaveBeenCalledWith('/monetization/checkout/', {
        success_url: 'http://localhost/billing/success?session_id={CHECKOUT_SESSION_ID}',
        cancel_url: 'http://localhost/billing/cancel',
      });
      expect(assignMock).toHaveBeenCalledWith('https://checkout.stripe.com/c/pay/cs_test_abc');
      expect(setAuthentication).toHaveBeenCalledWith(true);
      expect(localStorage.getItem('access_token')).toBe('access-token');
    });
  });
});
