/**
 * LogoUpload Component Tests
 *
 * Tests BEHAVIOR of the logo upload component:
 * - User can see current logo or "No logo" placeholder
 * - User can upload a new logo
 * - User can remove an existing logo
 * - Invalid files are rejected with appropriate messages
 * - Loading states are shown during upload
 */

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

// Mock the image upload hook
const mockUploadImage = jest.fn();
jest.mock('@/hooks/useImageUpload', () => ({
  useImageUpload: () => ({
    uploadImage: mockUploadImage,
    isUploading: false,
    error: null,
  }),
}));

// Mock Next.js Image component
jest.mock('next/image', () => ({
  __esModule: true,
  default: ({ src, alt, onError, ...props }: { src: string; alt: string; onError?: () => void }) => (
    // eslint-disable-next-line @next/next/no-img-element
    <img src={src} alt={alt} onError={onError} {...props} />
  ),
}));

describe('LogoUpload', () => {
  const mockOnLogoChange = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Display States', () => {
    it('shows "No logo" placeholder when no logo is set', () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      expect(screen.getByText('No logo')).toBeInTheDocument();
      expect(screen.getByText('Choose File')).toBeInTheDocument();
    });

    it('shows logo preview when logo URL is provided', () => {
      render(<LogoUpload currentLogoUrl="/test-logo.png" onLogoChange={mockOnLogoChange} />);

      const img = screen.getByAltText('Dealer logo');
      expect(img).toBeInTheDocument();
      expect(img).toHaveAttribute('src', '/test-logo.png');
    });

    it('shows Replace button when logo exists', () => {
      render(<LogoUpload currentLogoUrl="/test-logo.png" onLogoChange={mockOnLogoChange} />);

      expect(screen.getByText('Replace')).toBeInTheDocument();
      expect(screen.getByText('Remove')).toBeInTheDocument();
    });

    it('hides Remove button when no logo exists', () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      expect(screen.queryByText('Remove')).not.toBeInTheDocument();
    });
  });

  describe('Logo Removal', () => {
    it('calls onLogoChange with null when Remove is clicked', () => {
      render(<LogoUpload currentLogoUrl="/test-logo.png" onLogoChange={mockOnLogoChange} />);

      fireEvent.click(screen.getByText('Remove'));

      expect(mockOnLogoChange).toHaveBeenCalledWith(null);
    });
  });

  describe('File Validation', () => {
    it('rejects files that are not PNG, JPG, or WebP', async () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      const invalidFile = new File(['test'], 'test.gif', { type: 'image/gif' });

      fireEvent.change(input, { target: { files: [invalidFile] } });

      await waitFor(() => {
        expect(screen.getByText('Please upload a PNG, JPG, or WebP image')).toBeInTheDocument();
      });
      expect(mockUploadImage).not.toHaveBeenCalled();
    });

    it('rejects files larger than 5MB', async () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      // Create a mock file larger than 5MB.
      // Buffer.alloc is O(1) — sidesteps the multi-second cost of 'x'.repeat(6MB)
      // under parallel Jest worker contention which otherwise blows the test timeout.
      const largeFile = new File([Buffer.alloc(6 * 1024 * 1024)], 'large.png', { type: 'image/png' });
      Object.defineProperty(largeFile, 'size', { value: 6 * 1024 * 1024 });

      fireEvent.change(input, { target: { files: [largeFile] } });

      await waitFor(() => {
        expect(screen.getByText('Image must be under 5MB')).toBeInTheDocument();
      });
      expect(mockUploadImage).not.toHaveBeenCalled();
    }, 15000);

    it('accepts valid PNG files', async () => {
      mockUploadImage.mockResolvedValue('/uploaded-logo.png');
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      const validFile = new File(['test'], 'logo.png', { type: 'image/png' });

      fireEvent.change(input, { target: { files: [validFile] } });

      await waitFor(() => {
        expect(mockUploadImage).toHaveBeenCalledWith(validFile, 'logo');
      });
    });

    it('accepts valid JPG files', async () => {
      mockUploadImage.mockResolvedValue('/uploaded-logo.jpg');
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      const validFile = new File(['test'], 'logo.jpg', { type: 'image/jpeg' });

      fireEvent.change(input, { target: { files: [validFile] } });

      await waitFor(() => {
        expect(mockUploadImage).toHaveBeenCalledWith(validFile, 'logo');
      });
    });

    it('accepts valid WebP files', async () => {
      mockUploadImage.mockResolvedValue('/uploaded-logo.webp');
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      const validFile = new File(['test'], 'logo.webp', { type: 'image/webp' });

      fireEvent.change(input, { target: { files: [validFile] } });

      await waitFor(() => {
        expect(mockUploadImage).toHaveBeenCalledWith(validFile, 'logo');
      });
    });
  });

  describe('Successful Upload', () => {
    it('calls onLogoChange with uploaded URL after successful upload', async () => {
      mockUploadImage.mockResolvedValue('/uploads/new-logo.png');
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      const validFile = new File(['test'], 'logo.png', { type: 'image/png' });

      fireEvent.change(input, { target: { files: [validFile] } });

      await waitFor(() => {
        expect(mockOnLogoChange).toHaveBeenCalledWith('/uploads/new-logo.png');
      });
    });
  });

  describe('Accessibility', () => {
    it('has accessible file input with aria-label', () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      const input = screen.getByLabelText('Upload dealer logo');
      expect(input).toBeInTheDocument();
      expect(input).toHaveAttribute('type', 'file');
    });

    it('has visible label for the upload section', () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      expect(screen.getByText(/Dealer Logo/)).toBeInTheDocument();
    });

    it('shows format hints for users', () => {
      render(<LogoUpload currentLogoUrl={null} onLogoChange={mockOnLogoChange} />);

      expect(screen.getByText(/PNG, JPG, or WebP/)).toBeInTheDocument();
      expect(screen.getByText(/Max 5MB/)).toBeInTheDocument();
    });
  });
});
