import { render } from '@testing-library/react';
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import {
  ExternalLinkResolver,
  createExternalLinkRenderer,
} from './ExternalLinkRenderer';

interface TestData {
  id: string;
  title: string;
}

interface RendererWrapperProps {
  value: unknown;
  data: TestData;
  resolver: ExternalLinkResolver<TestData>;
  showNewTabIcon: boolean;
}

const data: TestData = {
  id: 'id',
  title: 'title',
};

const defaultProps: RendererWrapperProps = {
  resolver: () => 'imageUrl',
  showNewTabIcon: true,
  value: 'test-title',
  data,
};

const RendererWrapper: React.FC<RendererWrapperProps> = ({
  resolver,
  showNewTabIcon,
  value,
  data,
}) => {
  return (
    <>{createExternalLinkRenderer(resolver, showNewTabIcon)(value, data)}</>
  );
};

describe('createExternalLinkRenderer', () => {
  it('renders the component without crashing', () => {
    const { container } = render(<RendererWrapper {...defaultProps} />);
    expect(container).toBeTruthy();
  });

  it('generates hyperlink', () => {
    const mockResolver: ExternalLinkResolver<TestData> = (rowData) =>
      `/details/${rowData.id}`;

    const { container } = render(
      <RendererWrapper {...defaultProps} resolver={mockResolver} />,
    );

    const link = container.querySelector('a') as HTMLAnchorElement;

    expect(link.href).toContain(`/details/${data.id}`);
    expect(link.target).toBe('_blank');
    expect(link.rel).toBe('noopener noreferrer');
  });

  it('generates no hyperlink if url is falsy', () => {
    const mockResolver: ExternalLinkResolver<TestData> = (_rowData) =>
      undefined;

    const { container } = render(
      <RendererWrapper {...defaultProps} resolver={mockResolver} />,
    );

    const link = container.querySelector('a');
    const paragraph = container.querySelector('p');

    expect(link).not.toBeInTheDocument();
    expect(paragraph).toBeInTheDocument();
    expect(paragraph?.title).toBe('test-title');
  });

  it('renders column value and title attribute', () => {
    const mockValue = 'test';

    const { container } = render(
      <RendererWrapper {...defaultProps} value={mockValue} />,
    );

    const value = container.querySelector('p');

    expect(value?.textContent).toBe(mockValue);
    expect(value?.title).toBe(mockValue);
  });

  it('disables row click event when link is clicked', () => {
    const spy = vi.fn();

    const { container } = render(<RendererWrapper {...defaultProps} />);

    const link = container.querySelector('a') as HTMLAnchorElement;

    const event = new MouseEvent('click', { bubbles: true });
    Object.defineProperty(event, 'stopPropagation', {
      value: spy,
      writable: true,
    });

    link.dispatchEvent(event);

    expect(spy).toHaveBeenCalledTimes(1);
  });

  it(`renders 'Icon' by default`, () => {
    const { container } = render(<RendererWrapper {...defaultProps} />);

    const containerDiv = container.querySelector('.container');
    const icon = container.querySelector('.icons');

    expect(containerDiv?.classList.contains('noIcon')).toBe(false);
    expect(icon).toBeInTheDocument();
  });

  it(`does not render 'Icon' if 'showNewTabIcon' is set to false`, () => {
    const { container } = render(
      <RendererWrapper {...defaultProps} showNewTabIcon={false} />,
    );

    const containerDiv = container.querySelector('.container');
    const icon = container.querySelector('.icons');

    expect(containerDiv?.classList.contains('noIcon')).toBe(true);
    expect(icon).not.toBeInTheDocument();
  });
});
