import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { ThemeProvider } from '../../theme';

// next-intl echoes keys (and ignores interpolation params) so we assert on the state keys.
jest.mock('next-intl', () => ({
  useTranslations: () => (key: string) => key,
}));

import DocumentUpload from './DocumentUpload';

function renderUpload(props: Partial<React.ComponentProps<typeof DocumentUpload>> = {}) {
  const onUpload = props.onUpload ?? jest.fn().mockResolvedValue({ name: 'license.pdf' });
  const utils = render(
    <ThemeProvider>
      <DocumentUpload label="License" onUpload={onUpload} {...props} />
    </ThemeProvider>,
  );
  const input = utils.container.querySelector('input[type="file"]') as HTMLInputElement;
  return { ...utils, input, onUpload };
}

function selectFile(input: HTMLInputElement, file: File) {
  Object.defineProperty(input, 'files', { value: [file], configurable: true });
  fireEvent.change(input);
}

describe('<DocumentUpload/> component', () => {
  it('renders the field label and the idle choose zone', () => {
    const { container } = renderUpload();
    expect(screen.getByText('License')).toBeInTheDocument();
    expect(container.querySelector('[data-upload-state="idle"]')).toBeInTheDocument();
  });

  it('rejects a disallowed file type before uploading', () => {
    const { input, onUpload, container } = renderUpload();
    selectFile(input, new File(['x'], 'note.txt', { type: 'text/plain' }));
    expect(onUpload).not.toHaveBeenCalled();
    expect(container.querySelector('[data-upload-state="error"]')).toBeInTheDocument();
    expect(screen.getByText('upload_bad_type')).toBeInTheDocument();
  });

  it('rejects a file over the size cap before uploading', () => {
    const { input, onUpload } = renderUpload({ maxSizeBytes: 10 });
    const big = new File([new Uint8Array(50)], 'card.png', { type: 'image/png' });
    selectFile(input, big);
    expect(onUpload).not.toHaveBeenCalled();
    expect(screen.getByText('upload_too_large')).toBeInTheDocument();
  });

  it('uploads a valid file and shows the success state', async () => {
    const onUploaded = jest.fn();
    const { input, onUpload } = renderUpload({ onUploaded });
    selectFile(input, new File(['%PDF'], 'license.pdf', { type: 'application/pdf' }));
    await waitFor(() => expect(screen.getByText('upload_success')).toBeInTheDocument());
    expect(onUpload).toHaveBeenCalledTimes(1);
    expect(onUploaded).toHaveBeenCalledWith({ name: 'license.pdf' });
  });

  it('shows a retryable error when the upload fails', async () => {
    const onUpload = jest.fn().mockRejectedValue(new Error('boom'));
    const { input, container } = renderUpload({ onUpload });
    selectFile(input, new File(['%PDF'], 'license.pdf', { type: 'application/pdf' }));
    await waitFor(() => expect(container.querySelector('[data-upload-state="error"]')).toBeInTheDocument());
    expect(screen.getByText('upload_retry')).toBeInTheDocument();
  });

  it('renders the rejected state with its reason and a re-upload affordance', () => {
    const { container } = renderUpload({ rejected: true, rejectionReason: 'Blurry scan' });
    expect(container.querySelector('[data-upload-state="rejected"]')).toBeInTheDocument();
    expect(screen.getByText('Blurry scan')).toBeInTheDocument();
    expect(screen.getByText('upload_reupload')).toBeInTheDocument();
  });

  it('renders an already-uploaded document from server metadata', () => {
    const { container } = renderUpload({ existingDoc: { name: 'prior-license.pdf' } });
    expect(container.querySelector('[data-upload-state="success"]')).toBeInTheDocument();
    expect(screen.getByText('prior-license.pdf')).toBeInTheDocument();
  });
});
