import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';

const mockPut = vi.fn();
const mockSetData = vi.fn();
const mockTransform = vi.fn();

// Track the form's cap_usd so setData reflects into subsequent renders where it
// matters. The pause-toggle DOM behavior under test depends on the real useState
// inside the component, not on the form data, so a light stub is sufficient.
let formData: { cap_usd: string } = { cap_usd: '' };

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    usePage: vi.fn(() => ({
      props: {
        auth: { user: { name: 'Test User', email: 'test@example.com' } },
      },
    })),
    useForm: vi.fn(() => ({
      data: formData,
      setData: (key: string, value: string) => {
        mockSetData(key, value);
        formData = { ...formData, [key]: value };
      },
      put: mockPut,
      transform: mockTransform,
      processing: false,
      errors: {},
      isDirty: false,
    })),
    Head: () => null,
  };
});

vi.mock('@/hooks/useUnsavedChanges', () => ({ useUnsavedChanges: vi.fn() }));

vi.mock('@/Layouts/DashboardLayout', () => ({
  default: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="dashboard-layout">{children}</div>
  ),
}));

import Budget from './Budget';

describe('Budget — pause toggle', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    formData = { cap_usd: '' };
  });

  it('shows the cap input and "Save cap" when not paused (default for a positive cap)', () => {
    render(<Budget portfolio_cap={20} plan_max={200} plan_default_cap={200} mtd_spend={0} />);

    expect(screen.getByLabelText('Cap (USD per month)')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /save cap/i })).toBeInTheDocument();
    expect(screen.queryByText(/your spend cap is saved/i)).not.toBeInTheDocument();
  });

  it('defaults to paused when the loaded cap is 0', () => {
    render(<Budget portfolio_cap={0} plan_max={200} plan_default_cap={200} mtd_spend={5} />);

    const toggle = screen.getByRole('switch', { name: /pause all ai spend/i });
    expect(toggle).toBeChecked();
    // Cap input hidden, paused hint + paused button label shown.
    expect(screen.queryByLabelText('Cap (USD per month)')).not.toBeInTheDocument();
    expect(screen.getByText(/your spend cap is saved/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /ai spend paused/i })).toBeInTheDocument();
  });

  it('toggling pause on hides the cap input, sets cap_usd to 0, and swaps the button label', async () => {
    const user = userEvent.setup();
    render(<Budget portfolio_cap={20} plan_max={200} plan_default_cap={200} mtd_spend={0} />);

    expect(screen.getByLabelText('Cap (USD per month)')).toBeInTheDocument();

    await user.click(screen.getByRole('switch', { name: /pause all ai spend/i }));

    expect(mockSetData).toHaveBeenCalledWith('cap_usd', '0');
    expect(screen.queryByLabelText('Cap (USD per month)')).not.toBeInTheDocument();
    expect(screen.getByText(/your spend cap is saved/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /ai spend paused/i })).toBeInTheDocument();
  });

  it('toggling pause off restores the previous non-zero cap into the input', async () => {
    const user = userEvent.setup();
    render(<Budget portfolio_cap={35} plan_max={200} plan_default_cap={200} mtd_spend={0} />);

    const toggle = screen.getByRole('switch', { name: /pause all ai spend/i });
    await user.click(toggle); // pause on → stashes 35, sets 0
    await user.click(toggle); // pause off → restores 35

    // The last setData call on un-pause restores the stashed cap.
    expect(mockSetData).toHaveBeenLastCalledWith('cap_usd', '35');
    expect(screen.getByLabelText('Cap (USD per month)')).toBeInTheDocument();
  });

  it('submitting while paused forces cap_usd to 0 via transform', async () => {
    const user = userEvent.setup();
    // Load with a positive cap, then pause (makes the form dirty so Save enables).
    render(<Budget portfolio_cap={20} plan_max={200} plan_default_cap={200} mtd_spend={0} />);

    await user.click(screen.getByRole('switch', { name: /pause all ai spend/i }));
    await user.click(screen.getByRole('button', { name: /ai spend paused/i }));

    expect(mockTransform).toHaveBeenCalled();
    const transformFn = mockTransform.mock.calls[0][0] as (d: { cap_usd: string }) => {
      cap_usd: string;
    };
    expect(transformFn({ cap_usd: '99' })).toEqual({ cap_usd: '0' });
    expect(mockPut).toHaveBeenCalled();
  });
});
