/*
 * SonarQube
 * Copyright (C) 2009-2022 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { getDate, getMonth, getYear, subDays } from 'date-fns';
import selectEvent from 'react-select-event';
import { byPlaceholderText, byRole, byText } from 'testing-library-selector';
import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock';
import { now } from '../../../../helpers/dates';
import { getShortMonthName } from '../../../../helpers/l10n';
import { renderAppWithAdminContext } from '../../../../helpers/testReactTestingUtils';
import { AdminPageExtension } from '../../../../types/extension';
import routes from '../../routes';

jest.mock('../../../../api/settings');

const extensions = [
  { key: AdminPageExtension.GovernanceConsole, name: 'Portfolios' },
  { key: 'license/app', name: 'License Manager' },
  { key: 'license/support', name: 'Support' }
];

jest.mock('date-fns', () => {
  // Timezone will not play well so we fake the response from lib.
  const dateFns = jest.requireActual('date-fns');
  return {
    ...dateFns,
    endOfDay: jest.fn().mockImplementation(d => d),
    startOfDay: jest.fn().mockImplementation(d => d)
  };
});

jest.mock('../../../../helpers/dates', () => {
  return {
    ...jest.requireActual('../../../../helpers/dates'),
    now: jest.fn(() => new Date('2020-07-21T12:00:00Z'))
  };
});

const ui = {
  pageTitle: byRole('heading', { name: 'audit_logs.page' }),
  downloadButton: byRole('link', { name: 'download_verb' }),
  todayRadio: byRole('radio', { name: 'audit_logs.range_option.today' }),
  weekRadio: byRole('radio', { name: 'audit_logs.range_option.7days' }),
  monthRadio: byRole('radio', { name: 'audit_logs.range_option.30days' }),
  trimesterRadio: byRole('radio', { name: 'audit_logs.range_option.90days' }),
  customRadio: byRole('radio', { name: 'audit_logs.range_option.custom' }),
  downloadSentenceStart: byText('audit_logs.download_start.sentence.1'),
  startDateInput: byPlaceholderText('start_date'),
  endDateInput: byPlaceholderText('end_date')
};

let handler: SettingsServiceMock;

beforeAll(() => {
  handler = new SettingsServiceMock();
});

afterEach(() => handler.resetSettingvalues());

it('should handle download button click', async () => {
  const user = userEvent.setup();
  handler.setYearlyHousekeepingPolicy();
  renderAuditLogs();
  const downloadButton = await ui.downloadButton.find();
  expect(downloadButton).toBeInTheDocument();
  expect(downloadButton).toHaveAttribute(
    'href',
    '/api/audit_logs/download?from=2020-07-21T12%3A00%3A00.000Z&to=2020-07-21T12%3A00%3A00.000Z'
  );
  await user.click(ui.weekRadio.get());
  expect(downloadButton).toHaveAttribute(
    'href',
    '/api/audit_logs/download?from=2020-07-14T12%3A00%3A00.000Z&to=2020-07-21T12%3A00%3A00.000Z'
  );
  await user.click(ui.monthRadio.get());
  expect(downloadButton).toHaveAttribute(
    'href',
    '/api/audit_logs/download?from=2020-06-21T12%3A00%3A00.000Z&to=2020-07-21T12%3A00%3A00.000Z'
  );
  await user.click(ui.trimesterRadio.get());
  expect(downloadButton).toHaveAttribute(
    'href',
    '/api/audit_logs/download?from=2020-04-22T12%3A00%3A00.000Z&to=2020-07-21T12%3A00%3A00.000Z'
  );

  await user.click(downloadButton);

  expect(await ui.downloadButton.find()).toHaveAttribute('aria-disabled', 'true');
  expect(ui.downloadSentenceStart.get()).toBeInTheDocument();

  // Custom date
  const startDay = subDays(now(), 5);
  const endDate = subDays(now(), 1);
  await user.click(ui.customRadio.get());
  expect(ui.downloadButton.get()).toHaveAttribute('aria-disabled', 'true');
  await user.click(ui.startDateInput.get());

  await selectEvent.select(screen.getByRole('textbox', { name: 'select_month' }), [
    getShortMonthName(getMonth(startDay))
  ]);
  await selectEvent.select(screen.getByRole('textbox', { name: 'select_year' }), [
    getYear(startDay)
  ]);
  await user.click(screen.getByText(getDate(startDay)));
  await user.click(ui.endDateInput.get());

  await selectEvent.select(screen.getByRole('textbox', { name: 'select_month' }), [
    getShortMonthName(getMonth(endDate))
  ]);
  await selectEvent.select(screen.getByRole('textbox', { name: 'select_year' }), [
    getYear(endDate)
  ]);
  await user.click(screen.getByText(getDate(endDate)));

  expect(await ui.downloadButton.find()).toHaveAttribute('aria-disabled', 'false');
  await user.click(downloadButton);
  expect(await ui.downloadButton.find()).toHaveAttribute('aria-disabled', 'true');
});

it('should not render if governance is not enable', () => {
  renderAuditLogs([]);
  expect(ui.pageTitle.query()).not.toBeInTheDocument();
});

it('should show right option when keeping log for month', async () => {
  handler.unsetHousekeepingPolicy();
  renderAuditLogs();
  expect(await ui.pageTitle.find()).toBeInTheDocument();
  expect(ui.todayRadio.get()).toBeInTheDocument();
  expect(ui.weekRadio.get()).toBeInTheDocument();
  expect(ui.monthRadio.get()).toBeInTheDocument();
  expect(ui.customRadio.get()).toBeInTheDocument();
  expect(ui.trimesterRadio.query()).not.toBeInTheDocument();
});

it('should show right option when keeping log for year', async () => {
  handler.setYearlyHousekeepingPolicy();
  renderAuditLogs();
  expect(await ui.pageTitle.find()).toBeInTheDocument();
  expect(ui.todayRadio.get()).toBeInTheDocument();
  expect(ui.weekRadio.get()).toBeInTheDocument();
  expect(ui.monthRadio.get()).toBeInTheDocument();
  expect(ui.trimesterRadio.get()).toBeInTheDocument();
  expect(ui.customRadio.get()).toBeInTheDocument();
});

function renderAuditLogs(adminPages = extensions) {
  renderAppWithAdminContext('admin/audit', routes, {}, { adminPages });
}
