import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ManualCropUI from '@/components/ManualCropUI';
import type { CropBounds } from '@/hooks/useCropHandles';

describe('ManualCropUI Component', () => {
  const mockOnCropChange = vi.fn();
  const testImageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
  const imageDimensions = { width: 800, height: 600 };

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

  describe('Rendering', () => {
    it('should render component with image element', () => {
      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      const image = screen.getByAltText('Photo preview');
      expect(image).toBeInTheDocument();
    });

    it('should render container with proper structure', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      const cropContainer = container.querySelector('div');
      expect(cropContainer).toBeInTheDocument();
    });

    it('should show loading state when dimensions not provided', () => {
      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
        />
      );

      // Component should render image element even without dimensions
      const image = screen.getByAltText('Photo preview');
      expect(image).toBeInTheDocument();
      // Should show loading message
      expect(screen.getByText('Loading image...')).toBeInTheDocument();
    });

    it('should render "Use Full Photo" button when crop is active', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const button = screen.getByRole('button', { name: /use full photo/i });
      expect(button).toBeInTheDocument();
    });

    it('should not render "Use Full Photo" button when no crop is set', () => {
      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      const button = screen.queryByRole('button', { name: /use full photo/i });
      expect(button).not.toBeInTheDocument();
    });
  });

  describe('Crop Handle Rendering', () => {
    it('should render 8 drag handles when crop is active', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const handles = container.querySelectorAll('button[aria-label*="Drag"]');
      expect(handles.length).toBe(8); // 4 corners + 4 edges
    });

    it('should render corner handles', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      expect(screen.getByLabelText('Drag top-left handle')).toBeInTheDocument();
      expect(screen.getByLabelText('Drag top-right handle')).toBeInTheDocument();
      expect(screen.getByLabelText('Drag bottom-left handle')).toBeInTheDocument();
      expect(screen.getByLabelText('Drag bottom-right handle')).toBeInTheDocument();
    });

    it('should render edge handles', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      expect(screen.getByLabelText('Drag top handle')).toBeInTheDocument();
      expect(screen.getByLabelText('Drag right handle')).toBeInTheDocument();
      expect(screen.getByLabelText('Drag bottom handle')).toBeInTheDocument();
      expect(screen.getByLabelText('Drag left handle')).toBeInTheDocument();
    });

    it('should not render handles when no crop is active', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      const handles = container.querySelectorAll('button[aria-label*="Drag"]');
      expect(handles.length).toBe(0);
    });
  });

  describe('Semi-transparent Overlay', () => {
    it('should render overlay elements when crop is active', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const overlays = container.querySelectorAll('div[class*="bg-surface-container-lowest"]');
      expect(overlays.length).toBeGreaterThan(0);
    });

    it('should render bounding box with cyan border', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const bbox = container.querySelector('div[class*="border-cyan"]');
      expect(bbox).toBeInTheDocument();
      expect(bbox).toHaveClass('border-cyan-400');
    });

    it('should not render overlay when no crop is active', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      const overlays = container.querySelectorAll('div[class*="bg-surface-container-lowest/40"]');
      expect(overlays.length).toBe(0);
    });
  });

  describe('onCropChange Callback', () => {
    it('should call onCropChange with initial crop', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      expect(mockOnCropChange).toHaveBeenCalledWith(initialCrop);
    });

    it('should call onCropChange with null when no crop', () => {
      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

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

  describe('Use Full Photo Button', () => {
    it('should clear crop when "Use Full Photo" is clicked', async () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const user = userEvent.setup();
      const button = screen.getByRole('button', { name: /use full photo/i });

      await user.click(button);

      await waitFor(() => {
        expect(mockOnCropChange).toHaveBeenCalledWith(null);
      });
    });

    it('should hide handles after clearing crop', async () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const user = userEvent.setup();
      const button = screen.getByRole('button', { name: /use full photo/i });

      await user.click(button);

      await waitFor(() => {
        const handles = container.querySelectorAll('button[aria-label*="Drag"]');
        expect(handles.length).toBe(0);
      });
    });
  });

  describe('Error Handling', () => {
    it('should have error handling for image load failures', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      // Component should render without crashing
      const image = screen.getByAltText('Photo preview');
      expect(image).toBeInTheDocument();
    });
  });

  describe('Image Dimension Handling', () => {
    it('should use provided imageDimensions prop', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      // Component should render successfully with imageDimensions
      const image = screen.getByAltText('Photo preview');
      expect(image).toBeInTheDocument();
    });
  });

  describe('Touch Support', () => {
    it('should render handles with touch support', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const handle = screen.getByLabelText('Drag top-left handle');
      // Check that ontouchstart is defined (event handler exists)
      expect(handle).toBeDefined();
    });
  });

  describe('Mouse Support', () => {
    it('should render handles with mouse support', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const handle = screen.getByLabelText('Drag top-left handle');
      // Check that onmousedown is defined (event handler exists)
      expect(handle).toBeDefined();
    });
  });

  describe('Responsive Behavior', () => {
    it('should render handles with consistent sizing', () => {
      const initialCrop: CropBounds = { x: 100, y: 100, width: 200, height: 200 };

      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const handles = container.querySelectorAll('button[aria-label*="Drag"]');
      handles.forEach((handle) => {
        // Each handle should have width and height of 12px
        expect(handle).toHaveStyle('width: 12px');
        expect(handle).toHaveStyle('height: 12px');
      });
    });
  });

  describe('Minimum Crop Size Enforcement', () => {
    it('should enforce minimum crop size', () => {
      const tinyBounds: CropBounds = { x: 100, y: 100, width: 10, height: 10 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={tinyBounds}
        />
      );

      // onCropChange should be called with constrained bounds
      const calls = mockOnCropChange.mock.calls;
      const constrainedCrop = calls[calls.length - 1]?.[0];
      if (constrainedCrop) {
        expect(constrainedCrop.width).toBeGreaterThanOrEqual(100);
        expect(constrainedCrop.height).toBeGreaterThanOrEqual(100);
      }
    });
  });

  describe('Crop Bounds Display', () => {
    it('should display crop bounds debug information', () => {
      const initialCrop: CropBounds = { x: 150, y: 200, width: 250, height: 300 };

      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={initialCrop}
        />
      );

      const debugText = screen.getByText(/crop:/i);
      expect(debugText).toBeInTheDocument();
    });

    it('should not display bounds when no crop is set', () => {
      render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
        />
      );

      const debugText = screen.queryByText(/crop:/i);
      expect(debugText).not.toBeInTheDocument();
    });
  });

  describe('TypeScript Strict Mode Compliance', () => {
    it('should accept required and optional props', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
          imageDimensions={imageDimensions}
          initialCrop={{ x: 50, y: 50, width: 100, height: 100 }}
        />
      );

      expect(container).toBeInTheDocument();
    });

    it('should work with minimal required props', () => {
      const { container } = render(
        <ManualCropUI
          imageUrl={testImageUrl}
          onCropChange={mockOnCropChange}
        />
      );

      expect(container).toBeInTheDocument();
    });
  });
});
