import { render, screen, fireEvent, waitFor, within } from '@testing-library/react';
import { vi } from 'vitest';
import ItemDetailModal from '@/components/ItemDetailModal';
import { Item } from '@/lib/db';
import * as api from '@/lib/api';
import { toast } from 'react-hot-toast';

vi.mock('react-hot-toast');
vi.mock('@/lib/api');
vi.mock('@/components/ItemPhotoUpload', () => ({
  default: ({ itemId, onUploadSuccess, onError }: any) => (
    <div data-testid="item-photo-upload">
      <button
        data-testid="mock-upload-success"
        onClick={() =>
          onUploadSuccess({
            thumbnail_url: 'http://test.com/thumb.jpg',
            full_url: 'http://test.com/full.jpg',
            uploaded_at: '2026-04-21T10:00:00Z',
          })
        }
      >
        Upload Success
      </button>
      <button
        data-testid="mock-upload-error"
        onClick={() => onError('Upload failed')}
      >
        Upload Error
      </button>
    </div>
  ),
}));

describe('ItemDetailModal', () => {
  const mockItem: Item = {
    id: 1,
    name: 'Test Component',
    category: 'Electronics',
    quantity: 10,
    part_number: 'PN-001',
    barcode: 'BAR-001',
    type: 'IC',
    specs: 'Test specs',
    min_quantity: 5,
    image_url: 'http://test.com/photo.jpg',
  };

  const mockItemNoPhoto: Item = {
    id: 2,
    name: 'No Photo Item',
    category: 'Electronics',
    quantity: 5,
    part_number: 'PN-002',
    barcode: 'BAR-002',
    type: 'Resistor',
    specs: 'No photo specs',
    min_quantity: 2,
  };

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

  describe('Rendering', () => {
    it('should render modal with item details', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      expect(screen.getByText('Test Component')).toBeInTheDocument();
      expect(screen.getByText('Electronics')).toBeInTheDocument();
      expect(screen.getByText('IC')).toBeInTheDocument();
    });

    it('should display item photo when image_url exists', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      const photoImg = screen.getByAltText('Test Component') as HTMLImageElement;
      expect(photoImg).toBeInTheDocument();
      expect(photoImg.src).toContain('photo.jpg');
    });

    it('should show "No photo uploaded" when image_url is missing', () => {
      render(
        <ItemDetailModal
          item={mockItemNoPhoto}
          onClose={vi.fn()}
        />
      );
      expect(screen.getByText('No photo uploaded')).toBeInTheDocument();
    });

    it('should render item specifications in detail grid', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      expect(screen.getByText('PN-001')).toBeInTheDocument();
      expect(screen.getByText('BAR-001')).toBeInTheDocument();
    });
  });

  describe('Photo Replacement Button', () => {
    it('should show "Replace Photo" button when photo exists', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      expect(screen.getByText('Replace Photo')).toBeInTheDocument();
    });

    it('should show "Upload Photo" button when no photo exists', () => {
      render(
        <ItemDetailModal
          item={mockItemNoPhoto}
          onClose={vi.fn()}
        />
      );
      expect(screen.getByText('Upload Photo')).toBeInTheDocument();
    });

    it('should toggle photo upload UI on "Replace Photo" click', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      const replaceButton = screen.getByText('Replace Photo');
      fireEvent.click(replaceButton);
      expect(screen.getByTestId('item-photo-upload')).toBeInTheDocument();
      expect(screen.getByText('Upload New Photo')).toBeInTheDocument();
    });

    it('should hide photo upload UI on cancel', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      fireEvent.click(screen.getByText('Replace Photo'));
      expect(screen.getByTestId('item-photo-upload')).toBeInTheDocument();

      const closeButton = screen.getByLabelText('Cancel upload');
      fireEvent.click(closeButton);
      expect(screen.queryByTestId('item-photo-upload')).not.toBeInTheDocument();
    });
  });

  describe('Photo Upload Success', () => {
    it('should update photo and close upload UI on success', async () => {
      const onPhotoUpdated = vi.fn();
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
          onPhotoUpdated={onPhotoUpdated}
        />
      );

      fireEvent.click(screen.getByText('Replace Photo'));
      fireEvent.click(screen.getByTestId('mock-upload-success'));

      await waitFor(() => {
        expect(onPhotoUpdated).toHaveBeenCalledWith(
          expect.objectContaining({
            thumbnail_url: 'http://test.com/thumb.jpg',
          })
        );
      }, { timeout: 1000 });

      expect(screen.queryByTestId('item-photo-upload')).not.toBeInTheDocument();
    });

    it('should call onItemRefresh callback on upload success', async () => {
      const onItemRefresh = vi.fn();
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
          onItemRefresh={onItemRefresh}
        />
      );

      fireEvent.click(screen.getByText('Replace Photo'));
      fireEvent.click(screen.getByTestId('mock-upload-success'));

      await waitFor(() => {
        expect(onItemRefresh).toHaveBeenCalled();
      }, { timeout: 1000 });
    });
  });

  describe('Photo Upload Error', () => {
    it('should keep upload UI open on error', async () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );

      fireEvent.click(screen.getByText('Replace Photo'));
      fireEvent.click(screen.getByTestId('mock-upload-error'));

      await waitFor(() => {
        expect(screen.getByTestId('item-photo-upload')).toBeInTheDocument();
      }, { timeout: 1000 });
    });
  });

  describe('Photo Deletion', () => {
    it('should show delete button when photo exists', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );
      const buttons = screen.getAllByRole('button');
      const hasDeleteButton = buttons.some(b => b.className?.includes('rose-500'));
      expect(hasDeleteButton).toBe(true);
    });

    it('should call deleteItemPhoto API on delete confirmation', async () => {
      vi.mocked(api.inventoryApi.deleteItemPhoto).mockResolvedValue({ status: 'ok' });
      window.confirm = vi.fn(() => true);

      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );

      const buttons = screen.getAllByRole('button');
      const deleteButton = buttons.find(b => b.className?.includes('rose-500'));

      if (deleteButton) {
        fireEvent.click(deleteButton);

        await waitFor(() => {
          expect(api.inventoryApi.deleteItemPhoto).toHaveBeenCalledWith(mockItem.id);
        }, { timeout: 1000 });
      }
    });

    it('should show success toast on delete', async () => {
      vi.mocked(api.inventoryApi.deleteItemPhoto).mockResolvedValue({ status: 'ok' });
      window.confirm = vi.fn(() => true);

      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );

      const buttons = screen.getAllByRole('button');
      const deleteButton = buttons.find(b => b.className?.includes('rose-500'));

      if (deleteButton) {
        fireEvent.click(deleteButton);

        await waitFor(() => {
          expect(toast.success).toHaveBeenCalledWith('Photo deleted successfully');
        }, { timeout: 1000 });
      }
    });

    it('should not delete without confirmation', async () => {
      window.confirm = vi.fn(() => false);

      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );

      const buttons = screen.getAllByRole('button');
      const deleteButton = buttons.find(b => b.className?.includes('rose-500'));

      if (deleteButton) {
        fireEvent.click(deleteButton);
        expect(api.inventoryApi.deleteItemPhoto).not.toHaveBeenCalled();
      }
    });

    it('should call onItemRefresh on delete success', async () => {
      vi.mocked(api.inventoryApi.deleteItemPhoto).mockResolvedValue({ status: 'ok' });
      window.confirm = vi.fn(() => true);
      const onItemRefresh = vi.fn();

      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
          onItemRefresh={onItemRefresh}
        />
      );

      const buttons = screen.getAllByRole('button');
      const deleteButton = buttons.find(b => b.className?.includes('rose-500'));

      if (deleteButton) {
        fireEvent.click(deleteButton);

        await waitFor(() => {
          expect(onItemRefresh).toHaveBeenCalled();
        }, { timeout: 1000 });
      }
    });

    it('should show error toast on delete failure', async () => {
      vi.mocked(api.inventoryApi.deleteItemPhoto).mockRejectedValue(
        new Error('Delete failed')
      );
      window.confirm = vi.fn(() => true);

      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );

      const buttons = screen.getAllByRole('button');
      const deleteButton = buttons.find(b => b.className?.includes('rose-500'));

      if (deleteButton) {
        fireEvent.click(deleteButton);

        await waitFor(() => {
          expect(toast.error).toHaveBeenCalledWith('Delete failed');
        }, { timeout: 1000 });
      }
    });
  });

  describe('Modal Controls', () => {
    it('should call onClose when close button is clicked', () => {
      const onClose = vi.fn();
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={onClose}
        />
      );

      const closeButton = screen.getByLabelText('Close modal');
      fireEvent.click(closeButton);
      expect(onClose).toHaveBeenCalled();
    });

    it('should be scrollable when content exceeds viewport', () => {
      render(
        <ItemDetailModal
          item={mockItem}
          onClose={vi.fn()}
        />
      );

      const modalContent = screen.getByText('Test Component').closest('div');
      expect(modalContent?.parentElement?.className).toContain('max-h-[90vh]');
      expect(modalContent?.parentElement?.className).toContain('overflow-y-auto');
    });
  });
});
