import { type Page } from '@playwright/test';

import { test, expect } from '@grafana/plugin-e2e';

// Enable required feature toggles for Saved Searches (part of RuleList.v2)
test.use({
  featureToggles: {
    alertingListViewV2: true,
    alertingFilterV2: true,
    alertingSavedSearches: true,
    dashboardNewLayouts: false,
  },
});

/**
 * UI selectors for Saved Searches e2e tests.
 * Each selector is a function that takes the page and returns a locator.
 */
const ui = {
  // Main elements
  savedSearchesButton: (page: Page) => page.getByRole('button', { name: /saved searches/i }),
  dropdown: (page: Page) => page.getByRole('dialog', { name: /saved searches/i }),
  searchInput: (page: Page) => page.getByTestId('search-query-input'),

  // Save functionality
  saveButton: (page: Page) => page.getByRole('button', { name: /save current search/i }),
  saveConfirmButton: (page: Page) => page.getByRole('button', { name: /^save$/i }),
  saveNameInput: (page: Page) => page.getByPlaceholder(/enter a name/i),

  // Action menu
  actionsButton: (page: Page) => page.getByRole('button', { name: /actions/i }),
  renameMenuItem: (page: Page) => page.getByText(/rename/i),
  deleteMenuItem: (page: Page) => page.getByText(/^delete$/i),
  setAsDefaultMenuItem: (page: Page) => page.getByText(/set as default/i),
  deleteConfirmButton: (page: Page) => page.getByRole('button', { name: /^delete$/i }),

  // Indicators
  emptyState: (page: Page) => page.getByText(/no saved searches/i),
  defaultIcon: (page: Page) => page.getByRole('img', { name: /default search/i }),
  duplicateError: (page: Page) => page.getByText(/already exists/i),
};

/**
 * Helper to clear saved searches from UserStorage.
 * UserStorage persists data server-side via k8s API, so we need to delete via API.
 */
async function clearSavedSearches(page: Page) {
  // Get namespace and user info from Grafana config
  const storageInfo = await page.evaluate(() => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const bootData = (window as any).grafanaBootData;
    const user = bootData?.user;
    const userUID = user?.uid === '' || !user?.uid ? String(user?.id ?? 'anonymous') : user.uid;
    const resourceName = `alerting:${userUID}`;
    const namespace = bootData?.settings?.namespace || 'default';

    return { namespace, resourceName };
  });

  // Delete the UserStorage resource
  try {
    await page.request.delete(
      `/apis/userstorage.grafana.app/v0alpha1/namespaces/${storageInfo.namespace}/user-storage/${storageInfo.resourceName}`
    );
  } catch (error) {
    // Ignore 404 errors (resource doesn't exist)
    if (!(error && typeof error === 'object' && 'status' in error && error.status === 404)) {
      console.warn('Failed to clear saved searches:', error);
    }
  }

  // Also clear localStorage as fallback storage
  await page.evaluate(({ resourceName }) => {
    // The UserStorage key pattern is always `{resourceName}:{key}`
    // For saved searches, the key is 'savedSearches'
    const key = `${resourceName}:savedSearches`;
    window.localStorage.removeItem(key);
  }, storageInfo);

  // Clear session storage visited flag
  await page.evaluate(() => {
    window.sessionStorage.removeItem('grafana.alerting.ruleList.visited');
  });
}

test.describe(
  'Alert Rules - Saved Searches',
  {
    tag: ['@alerting'],
  },
  () => {
    test.beforeEach(async ({ page }) => {
      // Clear any saved searches from previous tests before navigating
      await page.goto('/alerting/list');
      await clearSavedSearches(page);
      await page.reload();
    });

    test.afterEach(async ({ page }) => {
      // Clean up saved searches after each test
      await clearSavedSearches(page);
    });

    test('should display Saved searches button', async ({ page }) => {
      await expect(ui.savedSearchesButton(page)).toBeVisible();
    });

    test('should open dropdown when clicking Saved searches button', async ({ page }) => {
      await ui.savedSearchesButton(page).click();

      await expect(ui.dropdown(page)).toBeVisible();
    });

    test('should show empty state when no saved searches exist', async ({ page }) => {
      // Storage is cleared in beforeEach, so we should see empty state
      await ui.savedSearchesButton(page).click();

      await expect(ui.emptyState(page)).toBeVisible();
    });

    test('should enable Save current search button when search query is entered', async ({ page }) => {
      // Enter a search query
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      // Open saved searches
      await ui.savedSearchesButton(page).click();

      await expect(ui.saveButton(page)).toBeEnabled();
    });

    test('should disable Save current search button when search query is empty', async ({ page }) => {
      await ui.savedSearchesButton(page).click();

      await expect(ui.saveButton(page)).toBeDisabled();
    });

    test('should save a new search', async ({ page }) => {
      // Enter a search query
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      // Open saved searches
      await ui.savedSearchesButton(page).click();

      // Click save button
      await ui.saveButton(page).click();

      // Enter name and save
      await ui.saveNameInput(page).fill('My Firing Rules');
      await ui.saveConfirmButton(page).click();

      // Verify the saved search appears in the list
      await expect(page.getByText('My Firing Rules')).toBeVisible();
    });

    test('should show validation error for duplicate name', async ({ page }) => {
      // First save a search
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      await ui.savedSearchesButton(page).click();

      await ui.saveButton(page).click();

      await ui.saveNameInput(page).fill('Duplicate Test');
      await ui.saveConfirmButton(page).click();

      // Try to save another with the same name
      await ui.saveButton(page).click();
      await ui.saveNameInput(page).fill('Duplicate Test');
      await ui.saveConfirmButton(page).click();

      // Verify validation error
      await expect(ui.duplicateError(page)).toBeVisible();
    });

    test('should apply a saved search', async ({ page }) => {
      // Create a saved search first
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      await ui.savedSearchesButton(page).click();

      await ui.saveButton(page).click();

      await ui.saveNameInput(page).fill('Firing Rules');
      await ui.saveConfirmButton(page).click();

      // Clear the search
      await ui.searchInput(page).clear();
      await ui.searchInput(page).press('Enter');

      // Apply the saved search by clicking the search name link
      await ui.savedSearchesButton(page).click();
      await page.getByRole('link', { name: 'Firing Rules' }).click();

      // Verify the search input is updated
      await expect(ui.searchInput(page)).toHaveValue('state:firing');
    });

    test('should rename a saved search', async ({ page }) => {
      // Create a saved search
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      await ui.savedSearchesButton(page).click();

      await ui.saveButton(page).click();

      await ui.saveNameInput(page).fill('Original Name');
      await ui.saveConfirmButton(page).click();

      // Open action menu and click rename
      await ui.actionsButton(page).click();
      await ui.renameMenuItem(page).click();

      // Enter new name
      const renameInput = page.getByRole('textbox', { name: /enter a name/i });
      await renameInput.clear();
      await renameInput.fill('Renamed Search');
      await page.keyboard.press('Enter');

      // Verify the name was updated
      await expect(page.getByText('Renamed Search')).toBeVisible();
      await expect(page.getByText('Original Name')).not.toBeVisible();
    });

    test('should delete a saved search', async ({ page }) => {
      // Create a saved search
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      await ui.savedSearchesButton(page).click();

      await ui.saveButton(page).click();

      await ui.saveNameInput(page).fill('To Delete');
      await ui.saveConfirmButton(page).click();

      // Verify it was saved
      await expect(page.getByText('To Delete')).toBeVisible();

      // Open action menu and click delete
      await ui.actionsButton(page).click();
      await ui.deleteMenuItem(page).click();

      // Confirm delete
      await ui.deleteConfirmButton(page).click();

      // Verify it was deleted
      await expect(page.getByText('To Delete')).not.toBeVisible();
    });

    test('should set a search as default', async ({ page }) => {
      // Create a saved search
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      await ui.savedSearchesButton(page).click();

      await ui.saveButton(page).click();

      await ui.saveNameInput(page).fill('Default Test');
      await ui.saveConfirmButton(page).click();

      // Set as default
      await ui.actionsButton(page).click();
      await ui.setAsDefaultMenuItem(page).click();

      // Verify the star icon appears (indicating default)
      await expect(ui.defaultIcon(page)).toBeVisible();
    });

    test('should close dropdown when pressing Escape', async ({ page }) => {
      await ui.savedSearchesButton(page).click();

      await expect(ui.dropdown(page)).toBeVisible();

      await page.keyboard.press('Escape');

      await expect(ui.dropdown(page)).not.toBeVisible();
    });

    test('should cancel save mode when pressing Escape', async ({ page }) => {
      // Enter a search query
      await ui.searchInput(page).fill('state:firing');
      await ui.searchInput(page).press('Enter');

      await ui.savedSearchesButton(page).click();

      // Start save mode
      await ui.saveButton(page).click();

      await expect(ui.saveNameInput(page)).toBeVisible();

      // Press Escape to cancel - this closes the entire dropdown
      await page.keyboard.press('Escape');

      // Verify the entire dialog is closed
      await expect(ui.dropdown(page)).not.toBeVisible();
      await expect(ui.saveButton(page)).not.toBeVisible();
    });
  }
);
