import React from 'react';
import { render as renderDom, screen, fireEvent } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { Card } from '../index';
import type { CardProps } from '../types';

describe('<Card>', () => {
    const render = (props?: Partial<CardProps>) =>
        // eslint-disable-next-line react/no-children-prop
        renderInAppContext(<Card children="test" {...props} />);

    test('renders content', () => {
        const bodyContent = 'TEST TEXT';
        render({ children: bodyContent });

        expect(screen.getByText(bodyContent)).toBeVisible();
    });

    describe('suite', () => {
        test('when unset returns Bootstrap Card', () => {
            render({ suite: false });

            expect(screen.queryByTestId('SuiteCard')).toBeNull();
            expect(screen.getByText('test')).toHaveClass('card');
        });

        test('when set returns Suite Card', () => {
            render({ suite: true });

            expect(screen.getByTestId('SuiteCard')).toBeInTheDocument();
            expect(screen.getByText('test')).not.toHaveClass('card');
            expect(screen.getByText('test')).toHaveClass('SuiteCard');
        });
    });

    describe('onClick', () => {
        test('sets clickable class', () => {
            render({ suite: true, onClick: vitest.fn() });

            expect(screen.getByText('test')).toHaveClass('SuiteCard-clickable');
        });

        test('reacts to clicks', () => {
            const onClick = vitest.fn();
            render({ suite: true, onClick });

            fireEvent.click(screen.getByText('test'));
            expect(onClick).toHaveBeenCalled();
        });
    });

    describe('href', () => {
        test('renders as link', () => {
            render({ suite: true, href: '/' });

            const card = screen.getByText('test');
            expect(card).toHaveRole('link');
            expect(card).toHaveAttribute('href', '/');
        });

        test('renders as div when disabled', () => {
            render({ suite: true, href: '/', disabled: true });

            const card = screen.getByText('test');
            expect(card).toHaveRole('button');
            expect(card).toHaveClass('disabled');
            expect(card).toHaveClass('SuiteCard-clickable');
            expect(card).not.toHaveAttribute('href', '/');
        });
    });

    describe('disabled', () => {
        test('sets disabled class', () => {
            render({ suite: true, disabled: true });

            expect(screen.getByText('test')).toHaveClass('disabled');
        });

        test('disables onClick', () => {
            const onClick = vitest.fn();
            render({ suite: true, onClick, disabled: true });

            fireEvent.click(screen.getByText('test'));
            expect(onClick).not.toHaveBeenCalled();
        });
    });

    describe('layout', () => {
        test('defaults to vertical', () => {
            render({ suite: true });

            expect(screen.getByText('test')).toHaveClass('vertical');
        });

        test('disables onClick', () => {
            render({ suite: true, layout: 'horizontal' });

            expect(screen.getByText('test')).toHaveClass('horizontal');
        });
    });

    describe('sub-components', () => {
        const components = [
            ['Body', 'body'],
            ['Header', 'header'],
            ['Title', 'title'],
            ['Subtitle', 'subtitle'],
            ['Link', 'link'],
            ['Text', 'text'],
            ['Footer', 'footer'],
            ['ImgOverlay', 'img-overlay'],
        ];

        test.each(components)('%s', (name, className) => {
            const Component = (Card as any)[name];
            renderDom(<Component>Test</Component>);
            expect(screen.getByText('Test')).toHaveClass(`card-${className}`);
        });

        test('Img', () => {
            const { container } = renderDom(<Card.Img />);
            expect(container.getElementsByClassName('card-img').item(0)).toBeInTheDocument();
        });
    });

    describe('className', () => {
        test('is passed through to container', () => {
            const className = 'test-class';
            render({ suite: true, className });

            expect(screen.getByTestId('SuiteCard')).toHaveClass(className);
        });
    });

    describe('testId', () => {
        test('is passed through to container', () => {
            const testId = 'custom-test-id';
            render({ suite: true, testId });

            expect(screen.getByTestId(testId)).toBeInTheDocument();
        });
    });
});
