/**
 * Custom E2E assertions — domain-specific checks for Agent Orchestrator.
 *
 * Uses exec() (cross-protocol safe wrapper) for DOM queries with dual
 * selectors to support both Tauri and Electrobun UIs.
 */

import { browser, expect } from '@wdio/globals';
import { exec } from './execute.ts';
import * as S from './selectors.ts';

/** Assert that a project card with the given name is visible in the grid */
export async function assertProjectVisible(name: string): Promise<void> {
  const found = await exec((n: string) => {
    const cards = document.querySelectorAll('.project-box, .project-card, .project-header');
    for (const card of cards) {
      if (card.textContent?.includes(n)) return true;
    }
    return false;
  }, name);
  expect(found).toBe(true);
}

/** Assert that at least one terminal pane responds (xterm container exists) */
export async function assertTerminalResponds(): Promise<void> {
  const xterm = await browser.$(S.XTERM);
  if (await xterm.isExisting()) {
    await expect(xterm).toBeDisplayed();
  }
}

/** Assert that a CSS custom property has changed after a theme switch */
export async function assertThemeApplied(varName = '--ctp-base'): Promise<void> {
  const value = await exec((v: string) => {
    return getComputedStyle(document.documentElement).getPropertyValue(v).trim();
  }, varName);
  expect(value.length).toBeGreaterThan(0);
}

/** Assert that a settings value persists (read via computed style or DOM) */
export async function assertSettingsPersist(selector: string): Promise<void> {
  const el = await browser.$(selector);
  if (await el.isExisting()) {
    await expect(el).toBeDisplayed();
  }
}

/** Assert the status bar is visible and contains expected sections */
export async function assertStatusBarComplete(): Promise<void> {
  await browser.waitUntil(
    async () =>
      exec(() => {
        const el = document.querySelector('[data-testid="status-bar"]')
          ?? document.querySelector('.status-bar');
        if (!el) return false;
        return getComputedStyle(el).display !== 'none';
      }),
    { timeout: 10_000, timeoutMsg: 'Status bar not visible within 10s' },
  );
}

/** Assert element count matches expected via DOM query */
export async function assertElementCount(
  selector: string,
  expected: number,
  comparison: 'eq' | 'gte' | 'lte' = 'eq',
): Promise<void> {
  const count = await exec((sel: string) => {
    return document.querySelectorAll(sel).length;
  }, selector);

  switch (comparison) {
    case 'eq': expect(count).toBe(expected); break;
    case 'gte': expect(count).toBeGreaterThanOrEqual(expected); break;
    case 'lte': expect(count).toBeLessThanOrEqual(expected); break;
  }
}

/** Assert an element has a specific CSS class */
export async function assertHasClass(selector: string, className: string): Promise<void> {
  const hasIt = await exec((sel: string, cls: string) => {
    const el = document.querySelector(sel);
    return el?.classList.contains(cls) ?? false;
  }, selector, className);
  expect(hasIt).toBe(true);
}
