// Copyright 2021 Northern.tech AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
import type { Page } from '@playwright/test';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween.js';

import test, { expect } from '../../fixtures/fixtures';
import { getTokenFromStorage } from '../../utils/commands';
import { releaseTag, selectors, timeouts } from '../../utils/constants';
import { locateReleaseByName, selectReleaseByName, triggerDeploymentCreation } from '../../utils/utils.ts';

dayjs.extend(isBetween);

const checkTimeFilter = async (page: Page, name: string, isSetToday?: boolean) => {
  const input = page.getByRole('group', { name });
  if (isSetToday) {
    await page.waitForTimeout(timeouts.oneSecond); // wait a little as sometimes the rendering hasn't fully finished when the following runs
    const shownDate = await input.textContent(); // will be shown as `YYYY-MM-DD${name}`
    await expect(shownDate).toContain(dayjs().format('YYYY-MM-DD'));
  }
  await expect(input).not.toHaveClass(/Mui-error/);
};

test.describe('Deployments', () => {
  let navbar;
  test.beforeEach(async ({ page }) => {
    navbar = page.locator('.leftFixed.leftNav');
    await navbar.getByRole('link', { name: /devices/i }).click();
    await page.waitForTimeout(timeouts.default);
    await navbar.getByRole('link', { name: 'Software', exact: true }).click();
    await page.waitForTimeout(timeouts.default);
  });
  test('check time filters before deployment', async ({ page }) => {
    await navbar.getByRole('link', { name: /deployments/i }).click();
    await page.getByRole('tab', { name: /finished/i }).click();
    await checkTimeFilter(page, 'From');
    await checkTimeFilter(page, 'To', true);
  });
  test('advanced deployment release filters', async ({ page }) => {
    const releaseName = 'mender-demo-artifact';
    await navbar.getByRole('link', { name: /deployments/i }).click();
    await page.click(`button:has-text('Create a deployment')`);
    await page.getByRole('button', { name: 'Select software' }).click();

    await page.getByRole('button', { name: 'Advanced filter' }).click();
    await page.getByRole('combobox', { name: 'Enter or Select tags...' }).click();
    await page.getByRole('option', { name: 'sometag' }).click();
    await page.waitForTimeout(timeouts.default);
    await expect(locateReleaseByName(page, releaseName)).toBeVisible();

    await page.getByRole('button', { name: 'Clear all' }).click();
    await page.getByRole('combobox', { name: 'Select Artifact type' }).click();
    await page.getByRole('option', { name: 'directory' }).click();
    await page.waitForTimeout(timeouts.default);
    await expect(locateReleaseByName(page, releaseName)).toBeVisible();
    await page.getByRole('button', { name: 'Clear all' }).click();
  });

  test('ensure release page filters are not used on deployment creation', async ({ page }) => {
    await page.getByPlaceholder(/select tags/i).fill(`${releaseTag.toLowerCase()},`);
    await navbar.getByRole('link', { name: /deployments/i }).click();
    await page
      .getByRole('button', { name: /create a deployment/i })
      .first()
      .click();
    await page.getByRole('button', { name: 'Select software' }).click();
    await expect(locateReleaseByName(page, 'mender-demo-artifact')).toBeVisible();
  });
  test('allows shortcut deployments', async ({ page }) => {
    // create an artifact to download first
    await page.getByText(/mender-demo-artifact/i).click();
    await page.click('.MuiSpeedDial-fab');
    await page.click('[aria-label="deploy"]');
    await page.waitForSelector(selectors.deviceGroupSelect, { timeout: timeouts.fiveSeconds });
    const deviceGroupSelect = await page.getByPlaceholder(/select a device group/i);
    await deviceGroupSelect.focus();
    await deviceGroupSelect.fill('All');
    await page.click(`#deployment-device-group-selection-listbox li:has-text('All devices')`);
    await triggerDeploymentCreation(page, page.getByRole('listitem').first().waitFor({ timeout: timeouts.tenSeconds }));
    await page.getByRole('tab', { name: /finished/i }).click();
    const pageContent = page.locator('.rightFluid.container');
    const listItem = pageContent.getByRole('listitem').first();
    await listItem.waitFor({ timeout: timeouts.sixtySeconds });
    const datetime = await listItem.locator('time').last().getAttribute('datetime');
    const time = dayjs(datetime);
    const earlier = dayjs().subtract(5, 'minutes');
    const now = dayjs();
    expect(time.isBetween(earlier, now));
  });

  test('allows shortcut device deployments', async ({ page }) => {
    await navbar.getByRole('link', { name: /devices/i }).click();
    // create an artifact to download first
    await page.getByText(/original/i).click();
    await page.click('.MuiSpeedDial-fab');
    await page.click('[aria-label="create-deployment"]');

    await selectReleaseByName(page, 'mender-demo-artifact');
    await triggerDeploymentCreation(page, expect(page.getByText(/Select a Release to deploy/i)).toHaveCount(0, { timeout: timeouts.tenSeconds }));
    await page.getByRole('tab', { name: /finished/i }).click();
    const pageContent = page.locator('.rightFluid.container');
    const listItem = pageContent.getByRole('listitem').first();
    await listItem.waitFor({ timeout: timeouts.sixtySeconds });
    const datetime = await listItem.locator('time').last().getAttribute('datetime');
    const time = dayjs(datetime);
    const earlier = dayjs().subtract(5, 'minutes');
    const now = dayjs();
    expect(time.isBetween(earlier, now));
    await checkTimeFilter(page, 'From', true);
    await checkTimeFilter(page, 'To', true);
  });

  test('allows group deployments', async ({ page }) => {
    await navbar.getByRole('link', { name: /deployments/i }).click();
    await page.click(`button:has-text('Create a deployment')`);

    await selectReleaseByName(page, 'mender-demo-artifact');

    await page.waitForSelector(selectors.deviceGroupSelect, { timeout: timeouts.fiveSeconds });
    const deviceGroupSelect = await page.getByPlaceholder(/select a device group/i);
    await deviceGroupSelect.focus();
    await deviceGroupSelect.fill('test');
    await page.click(`#deployment-device-group-selection-listbox li:has-text('testgroup')`);
    await triggerDeploymentCreation(page, expect(page.getByText(/Select a Release to deploy/i)).toHaveCount(0, { timeout: timeouts.tenSeconds }));
    await page.getByRole('tab', { name: /finished/i }).click();
    await page.getByRole('listitem').first().waitFor({ timeout: timeouts.sixtySeconds });
  });

  test('allows deployment filtering by name', async ({ demoDeviceName, page }) => {
    await navbar.getByRole('link', { name: /deployments/i }).click();
    await page.getByRole('tab', { name: /Finished/i }).click();
    await page.getByRole('combobox', { name: /Target devices/i }).click();
    await page.getByRole('combobox', { name: /Target devices/i }).fill(demoDeviceName);
    await page.getByRole('listitem').first().waitFor({ timeout: timeouts.fiveSeconds });
    const deployments = await page.getByRole('listitem').all();
    expect(deployments.length).toBeTruthy();
  });

  test('deployment pagination', async ({ baseUrl, page, request }) => {
    const token = await getTokenFromStorage(baseUrl);
    const pendingDeploymentRequests = Array.from({ length: 60 }, (_, index) => ({
      artifact_name: 'terminalImage',
      all_devices: true,
      max_devices: index,
      name: `deployment-${index + 1}`
    })).map(deployment =>
      request.post(`${baseUrl}api/management/v1/deployments/deployments`, { data: deployment, headers: { Authorization: `Bearer ${token}` } })
    );
    await Promise.all(pendingDeploymentRequests);
    await page.goto(`${baseUrl}ui/deployments`);
    await expect(page.getByText(/rows/i)).toBeVisible();
    await page.getByText(/rows/i).scrollIntoViewIfNeeded();
    // 10 clicks as anything leading outside of the 50 + something releases present (considering the 10 item page size)
    for (let clickAttempt = 0; clickAttempt < 10; clickAttempt++) {
      try {
        await page.getByRole('button', { name: 'next' }).click({ noWaitAfter: true, force: true });
      } catch {
        // the pagination component may re-render between clicks, momentarily hiding the button - just retry
        continue;
      }
    }
    await expect(page.getByText(/-([5|6]\d) of \1/)).toBeVisible(); // depending on the deployment speed of other tests there might be slightly more than 50
    await expect(page.getByText(/queued to start/i).first()).toBeVisible();
  });
});
