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

import { CREATE_BLUEPRINT, EDIT_BLUEPRINT } from '../../../../../constants';
import {
  CreateBlueprintRequest,
  CustomRepository,
  Repository,
} from '../../../../../store/imageBuilderApi';
import { mockBlueprintIds } from '../../../../fixtures/blueprints';
import {
  expectedCustomRepositories,
  expectedPayloadRepositories,
  repositoriesCreateBlueprintRequest,
} from '../../../../fixtures/editMode';
import {
  clickBack,
  clickNext,
  clickReviewAndFinish,
} from '../../wizardTestUtils';
import {
  blueprintRequest,
  clickRegisterLater,
  enterBlueprintName,
  interceptBlueprintRequest,
  interceptEditBlueprintRequest,
  openAndDismissSaveAndBuildModal,
  renderCreateMode,
  renderEditMode,
} from '../../wizardTestUtils';

const goToRepositoriesStep = async () => {
  const user = userEvent.setup();
  const guestImageCheckBox = await screen.findByRole('checkbox', {
    name: /virtualization guest image checkbox/i,
  });
  await waitFor(() => user.click(guestImageCheckBox));
  await clickNext(); // Registration
  await clickRegisterLater();
  await clickNext(); // OpenSCAP
  await clickNext(); // File system configuration
  await clickNext(); // Repository snapshot
  await clickNext(); // Custom repositories
};

const goToReviewStep = async () => {
  await clickNext(); // Additional packages
  await clickNext(); // Users
  await clickNext(); // Timezone
  await clickNext(); // Locale
  await clickNext(); // Hostname
  await clickNext(); // Kernel
  await clickNext(); // Firewall
  await clickNext(); // First Boot
  await clickNext(); // Details
  await enterBlueprintName();
  await clickNext(); // Review
};

const clickRevisitButton = async () => {
  const user = userEvent.setup();
  const expandable = await screen.findByTestId('content-expandable');
  const revisitButton = await within(expandable).findByTestId(
    'revisit-custom-repositories'
  );
  await waitFor(() => user.click(revisitButton));
};

const getFirstRepoCheckbox = async () =>
  await screen.findByRole('checkbox', {
    name: /select row 0/i,
  });

const getSecondRepoCheckbox = async () =>
  await screen.findByRole('checkbox', {
    name: /select row 1/i,
  });

const selectFirstRepository = async () => {
  const user = userEvent.setup();
  const row0Checkbox = await getFirstRepoCheckbox();
  await waitFor(async () => user.click(row0Checkbox));
};

const deselectFirstRepository = async () => {
  const user = userEvent.setup();
  const row0Checkbox = await getFirstRepoCheckbox();
  await waitFor(async () => user.click(row0Checkbox));
};

const clickBulkSelect = async () => {
  const user = userEvent.setup();
  const bulkSelectCheckbox = await screen.findByRole('checkbox', {
    name: /select all/i,
  });
  await waitFor(async () => user.click(bulkSelectCheckbox));
};

const toggleSelected = async () => {
  const user = userEvent.setup();
  const selectedButton = await screen.findByRole('button', {
    name: /selected repositories/i,
  });
  await waitFor(async () => user.click(selectedButton));
};

const toggleAll = async () => {
  const user = userEvent.setup();
  const allButton = await screen.findByRole('button', {
    name: /all repositories/i,
  });
  user.click(allButton);
};

const searchForRepository = async (searchTerm: string) => {
  const user = userEvent.setup();
  const searchInput = await screen.findByRole('textbox', {
    name: /search repositories/i,
  });
  await waitFor(() => user.type(searchInput, searchTerm));
};

describe('Step Custom repositories', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  const user = userEvent.setup();

  test('selected repositories stored in and retrieved from form state', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();

    let firstRepoCheckbox = (await getFirstRepoCheckbox()) as HTMLInputElement;

    expect(firstRepoCheckbox.checked).toEqual(false);
    user.click(firstRepoCheckbox);
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(true));

    await clickNext();
    await clickBack();

    firstRepoCheckbox = (await getFirstRepoCheckbox()) as HTMLInputElement;
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(true));
  });

  test('correct number of repositories is fetched', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();

    const select = await screen.findByRole('button', {
      name: /^select$/i,
    });
    user.click(select);
    await screen.findByText(/select page \(10 items\)/i);
  });

  test('press on Selected button to see selected repositories list', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();

    const firstRepoCheckbox =
      (await getFirstRepoCheckbox()) as HTMLInputElement;

    expect(firstRepoCheckbox.checked).toEqual(false);
    user.click(firstRepoCheckbox);
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(true));

    await toggleSelected();

    expect(firstRepoCheckbox.checked).toEqual(true);

    await clickNext();
    await clickBack();
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(true));
  });

  test('press on All button to see all repositories list', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();

    const firstRepoCheckbox =
      (await getFirstRepoCheckbox()) as HTMLInputElement;
    const secondRepoCheckbox =
      (await getSecondRepoCheckbox()) as HTMLInputElement;

    expect(firstRepoCheckbox.checked).toEqual(false);
    expect(secondRepoCheckbox.checked).toEqual(false);
    user.click(firstRepoCheckbox);
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(true));
    expect(secondRepoCheckbox.checked).toEqual(false);

    await toggleAll();

    expect(firstRepoCheckbox.checked).toEqual(true);
    expect(secondRepoCheckbox.checked).toEqual(false);

    await clickNext();
    await clickBack();

    expect(firstRepoCheckbox.checked).toEqual(true);
    await waitFor(() => expect(secondRepoCheckbox.checked).toEqual(false));
  });

  test('filter through selected repositories', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();

    const firstRepoCheckbox =
      (await getFirstRepoCheckbox()) as HTMLInputElement;

    expect(firstRepoCheckbox.checked).toEqual(false);
    user.click(firstRepoCheckbox);
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(true));

    await toggleSelected();
    expect(firstRepoCheckbox.checked).toEqual(true);
    await searchForRepository('13lk3');
    expect(firstRepoCheckbox.checked).toEqual(true);

    await clickNext();
    await clickBack();
    expect(firstRepoCheckbox.checked).toEqual(true);
    user.click(firstRepoCheckbox);
    await waitFor(() => expect(firstRepoCheckbox.checked).toEqual(false));
  });

  test('clicking Review and finish leads to Review', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();
    await clickReviewAndFinish();
    await screen.findByRole('heading', {
      name: /Review/,
    });
  });

  test('revisit step button on Review works', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();
    await selectFirstRepository();
    await goToReviewStep();
    await clickRevisitButton();
    await screen.findByRole('heading', { name: /Custom repositories/ });
  });
});

describe('Repositories request generated correctly', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  test('with custom repositories', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();
    await selectFirstRepository();
    await goToReviewStep();
    // informational modal pops up in the first test only as it's tied
    // to a 'imageBuilder.saveAndBuildModalSeen' variable in localStorage
    await openAndDismissSaveAndBuildModal();
    const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);

    const expectedRequest: CreateBlueprintRequest = {
      ...blueprintRequest,
      customizations: {
        custom_repositories: expectedCustomRepositories,
        payload_repositories: expectedPayloadRepositories,
      },
    };

    expect(receivedRequest).toEqual(expectedRequest);
  });

  const selectNginxRepository = async () => {
    const user = userEvent.setup();
    const search = await screen.findByLabelText('Search repositories');
    await waitFor(() => user.type(search, 'nginx stable repo'));
    await waitFor(
      () => expect(screen.getByText('nginx stable repo')).toBeInTheDocument
    );
    await selectFirstRepository();
  };

  const expectedNginxRepository: Repository = {
    baseurl: 'http://nginx.org/packages/centos/9/x86_64/',
    module_hotfixes: true,
    check_gpg: true,
    check_repo_gpg: false,
    gpgkey:
      '-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2.0.22 (GNU/Linux)\n\nmQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH\nW6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I\nQxnZZIbETgcSwFtDun0XiqPwPZgyuXVm9PAbLZRbfBzm8wR/3SWygqZBBLdQk5TE\nfDR+Eny/M1RVR4xClECONF9UBB2ejFdI1LD45APbP2hsN/piFByU1t7yK2gpFyRt\n97WzGHn9MV5/TL7AmRPM4pcr3JacmtCnxXeCZ8nLqedoSuHFuhwyDnlAbu8I16O5\nXRrfzhrHRJFM1JnIiGmzZi6zBvH0ItfyX6ttABEBAAG0KW5naW54IHNpZ25pbmcg\na2V5IDxzaWduaW5nLWtleUBuZ2lueC5jb20+iQE+BBMBAgAoAhsDBgsJCAcDAgYV\nCAIJCgsEFgIDAQIeAQIXgAUCV2K1+AUJGB4fQQAKCRCr9b2Ce9m/YloaB/9XGrol\nkocm7l/tsVjaBQCteXKuwsm4XhCuAQ6YAwA1L1UheGOG/aa2xJvrXE8X32tgcTjr\nKoYoXWcdxaFjlXGTt6jV85qRguUzvMOxxSEM2Dn115etN9piPl0Zz+4rkx8+2vJG\nF+eMlruPXg/zd88NvyLq5gGHEsFRBMVufYmHtNfcp4okC1klWiRIRSdp4QY1wdrN\n1O+/oCTl8Bzy6hcHjLIq3aoumcLxMjtBoclc/5OTioLDwSDfVx7rWyfRhcBzVbwD\noe/PD08AoAA6fxXvWjSxy+dGhEaXoTHjkCbz/l6NxrK3JFyauDgU4K4MytsZ1HDi\nMgMW8hZXxszoICTTiQEcBBABAgAGBQJOTkelAAoJEKZP1bF62zmo79oH/1XDb29S\nYtWp+MTJTPFEwlWRiyRuDXy3wBd/BpwBRIWfWzMs1gnCjNjk0EVBVGa2grvy9Jtx\nJKMd6l/PWXVucSt+U/+GO8rBkw14SdhqxaS2l14v6gyMeUrSbY3XfToGfwHC4sa/\nThn8X4jFaQ2XN5dAIzJGU1s5JA0tjEzUwCnmrKmyMlXZaoQVrmORGjCuH0I0aAFk\nRS0UtnB9HPpxhGVbs24xXZQnZDNbUQeulFxS4uP3OLDBAeCHl+v4t/uotIad8v6J\nSO93vc1evIje6lguE81HHmJn9noxPItvOvSMb2yPsE8mH4cJHRTFNSEhPW6ghmlf\nWa9ZwiVX5igxcvaIRgQQEQIABgUCTk5b0gAKCRDs8OkLLBcgg1G+AKCnacLb/+W6\ncflirUIExgZdUJqoogCeNPVwXiHEIVqithAM1pdY/gcaQZmIRgQQEQIABgUCTk5f\nYQAKCRCpN2E5pSTFPnNWAJ9gUozyiS+9jf2rJvqmJSeWuCgVRwCcCUFhXRCpQO2Y\nVa3l3WuB+rgKjsQ=\n=EWWI\n-----END PGP PUBLIC KEY BLOCK-----',
    rhsm: false,
  };

  const expectedNginxCustomRepository: CustomRepository = {
    baseurl: ['http://nginx.org/packages/centos/9/x86_64/'],
    module_hotfixes: true,
    check_gpg: true,
    check_repo_gpg: false,
    gpgkey: [
      '-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2.0.22 (GNU/Linux)\n\nmQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH\nW6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I\nQxnZZIbETgcSwFtDun0XiqPwPZgyuXVm9PAbLZRbfBzm8wR/3SWygqZBBLdQk5TE\nfDR+Eny/M1RVR4xClECONF9UBB2ejFdI1LD45APbP2hsN/piFByU1t7yK2gpFyRt\n97WzGHn9MV5/TL7AmRPM4pcr3JacmtCnxXeCZ8nLqedoSuHFuhwyDnlAbu8I16O5\nXRrfzhrHRJFM1JnIiGmzZi6zBvH0ItfyX6ttABEBAAG0KW5naW54IHNpZ25pbmcg\na2V5IDxzaWduaW5nLWtleUBuZ2lueC5jb20+iQE+BBMBAgAoAhsDBgsJCAcDAgYV\nCAIJCgsEFgIDAQIeAQIXgAUCV2K1+AUJGB4fQQAKCRCr9b2Ce9m/YloaB/9XGrol\nkocm7l/tsVjaBQCteXKuwsm4XhCuAQ6YAwA1L1UheGOG/aa2xJvrXE8X32tgcTjr\nKoYoXWcdxaFjlXGTt6jV85qRguUzvMOxxSEM2Dn115etN9piPl0Zz+4rkx8+2vJG\nF+eMlruPXg/zd88NvyLq5gGHEsFRBMVufYmHtNfcp4okC1klWiRIRSdp4QY1wdrN\n1O+/oCTl8Bzy6hcHjLIq3aoumcLxMjtBoclc/5OTioLDwSDfVx7rWyfRhcBzVbwD\noe/PD08AoAA6fxXvWjSxy+dGhEaXoTHjkCbz/l6NxrK3JFyauDgU4K4MytsZ1HDi\nMgMW8hZXxszoICTTiQEcBBABAgAGBQJOTkelAAoJEKZP1bF62zmo79oH/1XDb29S\nYtWp+MTJTPFEwlWRiyRuDXy3wBd/BpwBRIWfWzMs1gnCjNjk0EVBVGa2grvy9Jtx\nJKMd6l/PWXVucSt+U/+GO8rBkw14SdhqxaS2l14v6gyMeUrSbY3XfToGfwHC4sa/\nThn8X4jFaQ2XN5dAIzJGU1s5JA0tjEzUwCnmrKmyMlXZaoQVrmORGjCuH0I0aAFk\nRS0UtnB9HPpxhGVbs24xXZQnZDNbUQeulFxS4uP3OLDBAeCHl+v4t/uotIad8v6J\nSO93vc1evIje6lguE81HHmJn9noxPItvOvSMb2yPsE8mH4cJHRTFNSEhPW6ghmlf\nWa9ZwiVX5igxcvaIRgQQEQIABgUCTk5b0gAKCRDs8OkLLBcgg1G+AKCnacLb/+W6\ncflirUIExgZdUJqoogCeNPVwXiHEIVqithAM1pdY/gcaQZmIRgQQEQIABgUCTk5f\nYQAKCRCpN2E5pSTFPnNWAJ9gUozyiS+9jf2rJvqmJSeWuCgVRwCcCUFhXRCpQO2Y\nVa3l3WuB+rgKjsQ=\n=EWWI\n-----END PGP PUBLIC KEY BLOCK-----',
    ],
    id: 'f087f9ad-dfe6-4627-9d53-447d1a997de5',
    name: 'nginx stable repo',
  };

  test('with custom repository with module_hotfixes', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();
    await selectNginxRepository();
    await goToReviewStep();
    const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);

    const expectedRequest: CreateBlueprintRequest = {
      ...blueprintRequest,
      customizations: {
        custom_repositories: [expectedNginxCustomRepository],
        payload_repositories: [expectedNginxRepository],
      },
    };

    expect(receivedRequest).toEqual(expectedRequest);
  });

  test('deselecting a custom repository removes it from the request', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();
    await selectFirstRepository();
    await deselectFirstRepository();
    await goToReviewStep();
    const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);

    const expectedRequest = blueprintRequest;

    await waitFor(() => {
      expect(receivedRequest).toEqual(expectedRequest);
    });
  });

  test('bulk select', async () => {
    await renderCreateMode();
    await goToRepositoriesStep();
    await clickBulkSelect();
    await goToReviewStep();
    const receivedRequest = (await interceptBlueprintRequest(
      CREATE_BLUEPRINT
    )) as CreateBlueprintRequest;
    expect(receivedRequest.customizations.custom_repositories).toHaveLength(6);
    expect(receivedRequest.customizations.payload_repositories).toHaveLength(6);
  });
});

describe('Repositories edit mode', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  const user = userEvent.setup();

  test('edit mode works', async () => {
    const id = mockBlueprintIds['repositories'];
    await renderEditMode(id);

    // starts on review step
    const receivedRequest = await interceptEditBlueprintRequest(
      `${EDIT_BLUEPRINT}/${id}`
    );
    const expectedRequest = repositoriesCreateBlueprintRequest;
    await waitFor(() => expect(receivedRequest).toEqual(expectedRequest));
  });

  test('modal pops up when deselecting previously used repository', async () => {
    const id = mockBlueprintIds['repositories'];
    await renderEditMode(id);

    const customRepositories = await screen.findByRole('button', {
      name: /Custom repositories/,
    });

    user.click(customRepositories);

    await screen.findByText(
      /Removing previously added repositories may lead to issues with selected packages/i
    );

    await toggleSelected();

    const repoCheckbox = await getFirstRepoCheckbox();
    await waitFor(() => expect(repoCheckbox).toBeChecked());

    user.click(repoCheckbox);
    await screen.findByText(/Are you sure?/);
    const removeAnywayBtn = await screen.findByRole('button', {
      name: /Remove anyway/,
    });
    user.click(removeAnywayBtn);

    await waitFor(() =>
      expect(screen.queryByText(/Are you sure?/)).not.toBeInTheDocument()
    );

    await waitFor(() => expect(repoCheckbox).not.toBeChecked());
  });
});
