import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { ReportReviewDialog } from '../report-review-dialog';

const reportMock = vi.fn();
vi.mock('@/lib/api', () => ({
  api: {
    reviewReports: {
      report: (...a: unknown[]) => reportMock(...a),
    },
  },
}));

function wrap(node: React.ReactNode) {
  const qc = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  });
  return <QueryClientProvider client={qc}>{node}</QueryClientProvider>;
}

describe('ReportReviewDialog', () => {
  beforeEach(() => {
    reportMock.mockReset();
  });

  it('renders nothing when open=false', () => {
    const { container } = render(
      wrap(
        <ReportReviewDialog reviewId="rev-1" open={false} onClose={() => {}} />,
      ),
    );
    expect(container.firstChild).toBeNull();
  });

  it('renders all five reason options', () => {
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={() => {}} />),
    );
    expect(screen.getByDisplayValue('inappropriate')).toBeInTheDocument();
    expect(screen.getByDisplayValue('spam')).toBeInTheDocument();
    expect(screen.getByDisplayValue('not_about_purchase')).toBeInTheDocument();
    expect(screen.getByDisplayValue('personal_info')).toBeInTheDocument();
    expect(screen.getByDisplayValue('other')).toBeInTheDocument();
  });

  it('hides the reason_text textarea unless Other is selected', () => {
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={() => {}} />),
    );
    expect(screen.queryByLabelText(/Additional details/i)).toBeNull();

    fireEvent.click(screen.getByDisplayValue('other'));
    expect(screen.getByLabelText(/Additional details/i)).toBeInTheDocument();
  });

  it('disables Submit until a reason is selected', () => {
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={() => {}} />),
    );
    const submit = screen.getByRole('button', {
      name: /Submit report/i,
    }) as HTMLButtonElement;
    expect(submit.disabled).toBe(true);
    fireEvent.click(screen.getByLabelText(/Spam/i));
    expect(submit.disabled).toBe(false);
  });

  it('keeps Submit disabled with Other selected until reason_text is ≥ 10 chars', () => {
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={() => {}} />),
    );
    fireEvent.click(screen.getByDisplayValue('other'));
    const submit = screen.getByRole('button', {
      name: /Submit report/i,
    }) as HTMLButtonElement;
    expect(submit.disabled).toBe(true);

    fireEvent.change(screen.getByLabelText(/Additional details/i), {
      target: { value: 'short' },
    });
    expect(submit.disabled).toBe(true);

    fireEvent.change(screen.getByLabelText(/Additional details/i), {
      target: { value: 'A bit more context here.' },
    });
    expect(submit.disabled).toBe(false);
  });

  it('Submit calls api.reviewReports.report with reason only when not Other', async () => {
    reportMock.mockResolvedValueOnce({ data: { id: 'rep-1' } });
    const onClose = vi.fn();
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={onClose} />),
    );
    fireEvent.click(screen.getByLabelText(/Inappropriate/i));
    fireEvent.click(screen.getByRole('button', { name: /Submit report/i }));
    await waitFor(() =>
      expect(reportMock).toHaveBeenCalledWith('rev-1', {
        reason: 'inappropriate',
      }),
    );
    await waitFor(() => expect(onClose).toHaveBeenCalled());
  });

  it('Submit posts reason + reason_text when Other is selected', async () => {
    reportMock.mockResolvedValueOnce({ data: { id: 'rep-1' } });
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={() => {}} />),
    );
    fireEvent.click(screen.getByDisplayValue('other'));
    fireEvent.change(screen.getByLabelText(/Additional details/i), {
      target: { value: 'Says something rude.' },
    });
    fireEvent.click(screen.getByRole('button', { name: /Submit report/i }));
    await waitFor(() =>
      expect(reportMock).toHaveBeenCalledWith('rev-1', {
        reason: 'other',
        reason_text: 'Says something rude.',
      }),
    );
  });

  it('Cancel calls onClose without submitting', () => {
    const onClose = vi.fn();
    render(
      wrap(<ReportReviewDialog reviewId="rev-1" open onClose={onClose} />),
    );
    fireEvent.click(screen.getByRole('button', { name: /Cancel/i }));
    expect(onClose).toHaveBeenCalled();
    expect(reportMock).not.toHaveBeenCalled();
  });
});
