import { render, screen } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';

import {
  NJAccordion as AccordionLibrary,
  NJAccordionAction as AccordionActionLibrary,
  NJAccordionActions as AccordionActionsLibrary,
  NJAccordionItem as AccordionItemLibrary,
  NJAccordionItemContent as AccordionItemContentLibrary,
  NJAccordionItemHeader as AccordionItemHeaderLibrary
} from '../../../../lib/fluid-design-system-react';
import { NJAccordion as AccordionSource } from '../NJAccordion';
import { NJAccordionAction as AccordionActionSource } from '../NJAccordionAction';
import { NJAccordionActions as AccordionActionsSource } from '../NJAccordionActions';
import { NJAccordionItem as AccordionItemSource } from '../NJAccordionItem';
import { NJAccordionItemContent as AccordionItemContentSource } from '../NJAccordionItemContent';
import { NJAccordionItemHeader as AccordionItemHeaderSource } from '../NJAccordionItemHeader';

describe.each([
  {
    Accordion: AccordionSource,
    AccordionItem: AccordionItemSource,
    AccordionItemHeader: AccordionItemHeaderSource,
    AccordionItemContent: AccordionItemContentSource,
    AccordionActions: AccordionActionsSource,
    AccordionAction: AccordionActionSource,
    description: 'sources'
  },
  {
    Accordion: AccordionLibrary,
    AccordionItem: AccordionItemLibrary,
    AccordionItemHeader: AccordionItemHeaderLibrary,
    AccordionItemContent: AccordionItemContentLibrary,
    AccordionActions: AccordionActionsLibrary,
    AccordionAction: AccordionActionLibrary,
    description: 'global library'
  }
])(
  'using $description',
  ({
    Accordion,
    AccordionItem,
    AccordionItemHeader,
    AccordionItemContent,
    AccordionActions,
    AccordionAction
  }) => {
    describe('global', () => {
      it('renders correctly', () => {
        const { asFragment } = render(
          <Accordion>
            <AccordionItem>
              <AccordionItemHeader>Header</AccordionItemHeader>
              <AccordionItemContent>Triticums sunt aonidess de festus nixus.</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        expect(asFragment()).toMatchSnapshot();
      });

      it('open the accordion item on header click', async () => {
        const user = userEvent.setup();

        render(
          <Accordion>
            <AccordionItem>
              <AccordionItemHeader>Header</AccordionItemHeader>
              <AccordionItemContent>Triticums sunt aonidess de festus nixus.</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const header = screen.getByText('Header');
        const content = screen.queryByText('Triticums sunt aonidess de festus nixus.');

        await user.click(header);
        expect(content).toBeVisible();

        await user.click(header);
        expect(content).not.toBeVisible();
      });

      it('is visible if add open attribute', () => {
        render(
          <Accordion>
            <AccordionItem open>
              <AccordionItemHeader>Header 1</AccordionItemHeader>
              <AccordionItemContent>Content 1</AccordionItemContent>
            </AccordionItem>
            <AccordionItem>
              <AccordionItemHeader>Header 2</AccordionItemHeader>
              <AccordionItemContent>Content 2</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const content1 = screen.getByText('Content 1');
        const content2 = screen.getByText('Content 2');

        expect(content1).toBeVisible();
        expect(content2).not.toBeVisible();
      });

      it('works as exclusive accordion with name attribute', async () => {
        const user = userEvent.setup();

        render(
          <Accordion>
            <AccordionItem name="same-group">
              <AccordionItemHeader>Header 1</AccordionItemHeader>
              <AccordionItemContent>Content 1</AccordionItemContent>
            </AccordionItem>
            <AccordionItem name="same-group">
              <AccordionItemHeader>Header 2</AccordionItemHeader>
              <AccordionItemContent>Content 2</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const header1 = screen.getByText('Header 1');
        const content1 = screen.getByText('Content 1');
        const header2 = screen.getByText('Header 2');
        const content2 = screen.getByText('Content 2');

        await user.click(header1);
        expect(content1).toBeVisible();
        expect(content2).not.toBeVisible();

        await user.click(header2);
        expect(content2).toBeVisible();
        expect(content1).not.toBeVisible();
      });
    });

    describe('expand/collapse actions', () => {
      it('expand all when no opened', async () => {
        const user = userEvent.setup();

        render(
          <Accordion>
            <AccordionActions>
              <AccordionAction label="Expand All" action="expand" />
              <AccordionAction label="Collapse All" action="collapse" />
            </AccordionActions>
            <AccordionItem>
              <AccordionItemHeader>Header 1</AccordionItemHeader>
              <AccordionItemContent>Content 1</AccordionItemContent>
            </AccordionItem>
            <AccordionItem>
              <AccordionItemHeader>Header 2</AccordionItemHeader>
              <AccordionItemContent>Content 2</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const expandAll = screen.getByText('Expand All');
        const content1 = screen.getByText('Content 1');
        const content2 = screen.getByText('Content 2');

        expect(expandAll).toBeVisible();
        expect(content1).not.toBeVisible();
        expect(content2).not.toBeVisible();

        await user.click(expandAll);
        expect(content1).toBeVisible();
        expect(content2).toBeVisible();
      });

      it('collapse all when all opened', async () => {
        const user = userEvent.setup();

        render(
          <Accordion>
            <AccordionActions>
              <AccordionAction label="Expand All" action="expand" />
              <AccordionAction label="Collapse All" action="collapse" />
            </AccordionActions>
            <AccordionItem open>
              <AccordionItemHeader>Header 1</AccordionItemHeader>
              <AccordionItemContent>Content 1</AccordionItemContent>
            </AccordionItem>
            <AccordionItem open>
              <AccordionItemHeader>Header 2</AccordionItemHeader>
              <AccordionItemContent>Content 2</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const collapseAll = screen.getByText('Collapse All');
        const content1 = screen.getByText('Content 1');
        const content2 = screen.getByText('Content 2');

        expect(collapseAll).toBeVisible();
        expect(content1).toBeVisible();
        expect(content2).toBeVisible();

        await user.click(collapseAll);
        expect(content1).not.toBeVisible();
        expect(content2).not.toBeVisible();
      });

      it('expand all when some already opened', async () => {
        const user = userEvent.setup();

        render(
          <Accordion>
            <AccordionActions>
              <AccordionAction label="Expand All" action="expand" />
              <AccordionAction label="Collapse All" action="collapse" />
            </AccordionActions>
            <AccordionItem open>
              <AccordionItemHeader>Header 1</AccordionItemHeader>
              <AccordionItemContent>Content 1</AccordionItemContent>
            </AccordionItem>
            <AccordionItem>
              <AccordionItemHeader>Header 2</AccordionItemHeader>
              <AccordionItemContent>Content 2</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const expandAll = screen.getByText('Expand All');
        const content1 = screen.getByText('Content 1');
        const content2 = screen.getByText('Content 2');

        expect(expandAll).toBeVisible();
        expect(content1).toBeVisible();
        expect(content2).not.toBeVisible();

        await user.click(expandAll);
        expect(content1).toBeVisible();
        expect(content2).toBeVisible();
      });

      it('collapse all when some already closed', async () => {
        const user = userEvent.setup();

        render(
          <Accordion>
            <AccordionActions>
              <AccordionAction label="Expand All" action="expand" />
              <AccordionAction label="Collapse All" action="collapse" />
            </AccordionActions>
            <AccordionItem>
              <AccordionItemHeader>Header 1</AccordionItemHeader>
              <AccordionItemContent>Content 1</AccordionItemContent>
            </AccordionItem>
            <AccordionItem open>
              <AccordionItemHeader>Header 2</AccordionItemHeader>
              <AccordionItemContent>Content 2</AccordionItemContent>
            </AccordionItem>
          </Accordion>
        );

        const collapseAll = screen.getByText('Collapse All');
        const content1 = screen.getByText('Content 1');
        const content2 = screen.getByText('Content 2');

        expect(collapseAll).toBeVisible();
        expect(content1).not.toBeVisible();
        expect(content2).toBeVisible();

        await user.click(collapseAll);
        expect(content1).not.toBeVisible();
        expect(content2).not.toBeVisible();
      });
    });
  }
);
