/**
 * Security Dashboard E2E Tests
 *
 * Tests the Security (Cerberus) dashboard functionality including:
 * - Page loading and layout
 * - Module toggle states (CrowdSec, ACL, WAF, Rate Limiting)
 * - Status indicators
 * - Navigation to sub-pages
 *
 * @see /projects/Charon/docs/plans/current_spec.md - Phase 3
 */

import { test, expect, loginUser } from '../fixtures/auth-fixtures';
import { request } from '@playwright/test';
import type { APIRequestContext } from '@playwright/test';
import { waitForLoadingComplete, waitForToast } from '../utils/wait-helpers';
import {
  captureSecurityState,
  restoreSecurityState,
  CapturedSecurityState,
} from '../utils/security-helpers';

test.describe('Security Dashboard', () => {
  test.beforeEach(async ({ page, adminUser }) => {
    await loginUser(page, adminUser);
    await waitForLoadingComplete(page);
    await page.goto('/security');
    await waitForLoadingComplete(page);
  });

  test.describe('Page Loading', () => {
    test('should display security dashboard page title', async ({ page }) => {
      await expect(page.getByRole('heading', { name: /security/i }).first()).toBeVisible();
    });

    test('should display Cerberus dashboard header', async ({ page }) => {
      await expect(page.getByText(/cerberus.*dashboard/i)).toBeVisible();
    });

    test('should show all 4 security module cards', async ({ page }) => {
      await test.step('Verify CrowdSec card exists', async () => {
        await expect(page.getByText(/crowdsec/i).first()).toBeVisible();
      });

      await test.step('Verify ACL card exists', async () => {
        await expect(page.getByText(/access.*control/i).first()).toBeVisible();
      });

      await test.step('Verify WAF card exists', async () => {
        await expect(page.getByText(/coraza.*waf|waf/i).first()).toBeVisible();
      });

      await test.step('Verify Rate Limiting card exists', async () => {
        await expect(page.getByText(/rate.*limiting/i).first()).toBeVisible();
      });
    });

    test('should display layer badges for each module', async ({ page }) => {
      await expect(page.getByText(/layer.*1/i)).toBeVisible();
      await expect(page.getByText(/layer.*2/i)).toBeVisible();
      await expect(page.getByText(/layer.*3/i)).toBeVisible();
      await expect(page.getByText(/layer.*4/i)).toBeVisible();
    });

    test('should show audit logs button in header', async ({ page }) => {
      const auditLogsButton = page.getByRole('button', { name: /audit.*logs/i });
      await expect(auditLogsButton).toBeVisible();
    });

    test('should show docs button in header', async ({ page }) => {
      const docsButton = page.getByRole('button', { name: /docs/i });
      await expect(docsButton).toBeVisible();
    });
  });

  test.describe('Module Status Indicators', () => {
    test('should show enabled/disabled badge for each module', async ({ page }) => {
      // Each card should have an enabled or disabled badge
      // Look for text that matches enabled/disabled patterns
      // The Badge component may use various styling approaches
      await page.waitForTimeout(500); // Wait for UI to settle

      const enabledTexts = page.getByText(/^enabled$/i);
      const disabledTexts = page.getByText(/^disabled$/i);

      const enabledCount = await enabledTexts.count();
      const disabledCount = await disabledTexts.count();

      // Should have at least 4 status badges (one per security layer card)
      expect(enabledCount + disabledCount).toBeGreaterThanOrEqual(4);
    });

    test('should display CrowdSec toggle switch', async ({ page }) => {
      const toggle = page.getByTestId('toggle-crowdsec');
      await expect(toggle).toBeVisible();
    });

    test('should display ACL toggle switch', async ({ page }) => {
      const toggle = page.getByTestId('toggle-acl');
      await expect(toggle).toBeVisible();
    });

    test('should display WAF toggle switch', async ({ page }) => {
      const toggle = page.getByTestId('toggle-waf');
      await expect(toggle).toBeVisible();
    });

    test('should display Rate Limiting toggle switch', async ({ page }) => {
      const toggle = page.getByTestId('toggle-rate-limit');
      await expect(toggle).toBeVisible();
    });
  });

  test.describe('Module Toggle Actions', () => {
    // Capture state ONCE for this describe block
    let originalState: CapturedSecurityState;

    test.beforeAll(async ({ request: reqFixture }) => {
      try {
        originalState = await captureSecurityState(reqFixture);
      } catch (error) {
        console.warn('Could not capture initial security state:', error);
      }
    });

    test.afterAll(async () => {
      // CRITICAL: Restore original state even if tests fail
      if (!originalState) {
        return;
      }

      // Create fresh request context for cleanup (cannot reuse fixture from beforeAll)
      const cleanupRequest = await request.newContext({
        baseURL: 'http://localhost:8080',
      });

      try {
        await restoreSecurityState(cleanupRequest, originalState);
        console.log('✓ Security state restored after toggle tests');
      } catch (error) {
        console.error('Failed to restore security state:', error);
      } finally {
        await cleanupRequest.dispose();
      }
    });

    test('should toggle ACL enabled/disabled', async ({ page }) => {
      const toggle = page.getByTestId('toggle-acl');

      const isDisabled = await toggle.isDisabled();
      if (isDisabled) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Toggle is disabled because Cerberus security is not enabled',
        });
        test.skip();
        return;
      }

      await test.step('Toggle ACL state', async () => {
        await page.waitForLoadState('networkidle');
        await toggle.scrollIntoViewIfNeeded();
        await page.waitForTimeout(200);
        await toggle.click({ force: true });
        await waitForToast(page, /updated|success|enabled|disabled/i, 10000);
      });

      // NOTE: Do NOT toggle back here - afterAll handles cleanup
    });

    test('should toggle WAF enabled/disabled', async ({ page }) => {
      const toggle = page.getByTestId('toggle-waf');

      const isDisabled = await toggle.isDisabled();
      if (isDisabled) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Toggle is disabled because Cerberus security is not enabled',
        });
        test.skip();
        return;
      }

      await test.step('Toggle WAF state', async () => {
        await page.waitForLoadState('networkidle');
        await toggle.scrollIntoViewIfNeeded();
        await page.waitForTimeout(200);
        await toggle.click({ force: true });
        await waitForToast(page, /updated|success|enabled|disabled/i, 10000);
      });

      // NOTE: Do NOT toggle back here - afterAll handles cleanup
    });

    test('should toggle Rate Limiting enabled/disabled', async ({ page }) => {
      const toggle = page.getByTestId('toggle-rate-limit');

      const isDisabled = await toggle.isDisabled();
      if (isDisabled) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Toggle is disabled because Cerberus security is not enabled',
        });
        test.skip();
        return;
      }

      await test.step('Toggle Rate Limit state', async () => {
        await page.waitForLoadState('networkidle');
        await toggle.scrollIntoViewIfNeeded();
        await page.waitForTimeout(200);
        await toggle.click({ force: true });
        await waitForToast(page, /updated|success|enabled|disabled/i, 10000);
      });

      // NOTE: Do NOT toggle back here - afterAll handles cleanup
    });

    test('should persist toggle state after page reload', async ({ page }) => {
      const toggle = page.getByTestId('toggle-acl');

      const isDisabled = await toggle.isDisabled();
      if (isDisabled) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Toggle is disabled because Cerberus security is not enabled',
        });
        test.skip();
        return;
      }

      const initialChecked = await toggle.isChecked();

      await test.step('Toggle ACL state', async () => {
        await page.waitForLoadState('networkidle');
        await toggle.scrollIntoViewIfNeeded();
        await page.waitForTimeout(200);
        await toggle.click({ force: true });
        await waitForToast(page, /updated|success|enabled|disabled/i, 10000);
      });

      await test.step('Reload page', async () => {
        await page.reload();
        await waitForLoadingComplete(page);
      });

      await test.step('Verify state persisted', async () => {
        const newChecked = await page.getByTestId('toggle-acl').isChecked();
        expect(newChecked).toBe(!initialChecked);
      });

      // NOTE: Do NOT restore here - afterAll handles cleanup
    });
  });

  test.describe('Navigation', () => {
    test('should navigate to CrowdSec page when configure clicked', async ({ page }) => {
      // Find the CrowdSec card by locating the configure button within a container that has CrowdSec text
      // Cards use rounded-lg border classes, not [class*="card"]
      const crowdsecSection = page.locator('div').filter({ hasText: /crowdsec/i }).filter({ has: page.getByRole('button', { name: /configure/i }) }).first();
      const configureButton = crowdsecSection.getByRole('button', { name: /configure/i });

      // Button may be disabled when Cerberus is off
      const isDisabled = await configureButton.isDisabled().catch(() => true);
      if (isDisabled) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Configure button is disabled because Cerberus security is not enabled'
        });
        test.skip();
        return;
      }

      // Wait for any loading overlays to disappear
      await page.waitForLoadState('networkidle');
      await page.waitForTimeout(300);

      // Scroll element into view and use force click to bypass pointer interception
      await configureButton.scrollIntoViewIfNeeded();
      await configureButton.click({ force: true });
      await expect(page).toHaveURL(/\/security\/crowdsec/);
    });

    test('should navigate to Access Lists page when clicked', async ({ page }) => {
      // The ACL card has a "Manage Lists" or "Configure" button
      // Find button by looking for buttons with matching text within the page
      const allConfigButtons = page.getByRole('button', { name: /manage.*lists|configure/i });
      const count = await allConfigButtons.count();

      // The ACL button should be the second configure button (after CrowdSec)
      // Or we can find it near the "Access Control" or "ACL" text
      let aclButton = null;
      for (let i = 0; i < count; i++) {
        const btn = allConfigButtons.nth(i);
        const btnText = await btn.textContent();
        // The ACL button says "Manage Lists" when enabled, "Configure" when disabled
        if (btnText?.match(/manage.*lists/i)) {
          aclButton = btn;
          break;
        }
      }

      // Fallback to second configure button if no "Manage Lists" found
      if (!aclButton) {
        aclButton = allConfigButtons.nth(1);
      }

      // Wait for any loading overlays and scroll into view
      await page.waitForLoadState('networkidle');
      await aclButton.scrollIntoViewIfNeeded();
      await page.waitForTimeout(200);
      await aclButton.click({ force: true });
      await expect(page).toHaveURL(/\/security\/access-lists|\/access-lists/);
    });

    test('should navigate to WAF page when configure clicked', async ({ page }) => {
      // WAF is Layer 3 - the third configure button in the security cards grid
      const allConfigButtons = page.getByRole('button', { name: /configure/i });
      const count = await allConfigButtons.count();

      // Should have at least 3 configure buttons (CrowdSec, ACL/Manage Lists, WAF)
      if (count < 3) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Not enough configure buttons found on page'
        });
        test.skip();
        return;
      }

      // WAF is the 3rd configure button (index 2)
      const wafButton = allConfigButtons.nth(2);

      // Wait and scroll into view
      await page.waitForLoadState('networkidle');
      await wafButton.scrollIntoViewIfNeeded();
      await page.waitForTimeout(200);
      await wafButton.click({ force: true });
      await expect(page).toHaveURL(/\/security\/waf/);
    });

    test('should navigate to Rate Limiting page when configure clicked', async ({ page }) => {
      // Rate Limiting is Layer 4 - the fourth configure button in the security cards grid
      const allConfigButtons = page.getByRole('button', { name: /configure/i });
      const count = await allConfigButtons.count();

      // Should have at least 4 configure buttons
      if (count < 4) {
        test.info().annotations.push({
          type: 'skip-reason',
          description: 'Not enough configure buttons found on page'
        });
        test.skip();
        return;
      }

      // Rate Limit is the 4th configure button (index 3)
      const rateLimitButton = allConfigButtons.nth(3);

      // Wait and scroll into view
      await page.waitForLoadState('networkidle');
      await rateLimitButton.scrollIntoViewIfNeeded();
      await page.waitForTimeout(200);
      await rateLimitButton.click({ force: true });
      await expect(page).toHaveURL(/\/security\/rate-limiting/);
    });

    test('should navigate to Audit Logs page', async ({ page }) => {
      const auditLogsButton = page.getByRole('button', { name: /audit.*logs/i });

      await auditLogsButton.click();
      await expect(page).toHaveURL(/\/security\/audit-logs/);
    });
  });

  test.describe('Admin Whitelist', () => {
    test('should display admin whitelist section when Cerberus enabled', async ({ page }) => {
      // Check if the admin whitelist input is visible (only shown when Cerberus is enabled)
      const whitelistInput = page.getByPlaceholder(/192\.168|cidr/i);
      const isVisible = await whitelistInput.isVisible().catch(() => false);

      if (isVisible) {
        await expect(whitelistInput).toBeVisible();
      } else {
        // Cerberus might be disabled - just verify the page loaded correctly
        // by checking for the Cerberus Dashboard header which is always visible
        const cerberusHeader = page.getByText(/cerberus.*dashboard/i);
        await expect(cerberusHeader).toBeVisible();

        test.info().annotations.push({
          type: 'info',
          description: 'Admin whitelist section not visible - Cerberus may be disabled'
        });
      }
    });
  });

  test.describe('Accessibility', () => {
    test('should have accessible toggle switches with labels', async ({ page }) => {
      // Each toggle should be within a tooltip that describes its purpose
      // The Switch component uses an input[type="checkbox"] under the hood
      const toggles = [
        page.getByTestId('toggle-crowdsec'),
        page.getByTestId('toggle-acl'),
        page.getByTestId('toggle-waf'),
        page.getByTestId('toggle-rate-limit'),
      ];

      for (const toggle of toggles) {
        await expect(toggle).toBeVisible();
        // Switch uses checkbox input type (visually styled as toggle)
        await expect(toggle).toHaveAttribute('type', 'checkbox');
      }
    });

    test('should navigate with keyboard', async ({ page }) => {
      await test.step('Tab through header buttons', async () => {
        await page.keyboard.press('Tab');
        await page.keyboard.press('Tab');
        // Should be able to tab to various interactive elements
      });
    });
  });
});
