import { Page, Locator, PlaywrightTestConfig } from '@playwright/test';
export { expect } from '@playwright/test';
import winston from 'winston';
import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
import { RuleObject } from 'axe-core';

interface SafeWaitForURLOptions {
    timeout?: number;
    waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle';
    maxRetries?: number;
}
/**
 * Check if the current browser is Firefox
 */
declare function isFirefox(page: Page): boolean;
/**
 * Safe wrapper around page.waitForURL that handles browser-specific navigation errors
 *
 * Firefox has stricter navigation lifecycle handling that can cause NS_BINDING_ABORTED
 * errors when multiple rapid navigations occur (React router redirects, auth redirects).
 *
 * Safari can throw "Navigation canceled by policy check" errors during cross-origin
 * navigations or when security policies interrupt the navigation flow.
 *
 * This utility:
 * 1. Uses `waitUntil: 'commit'` for Firefox (faster, avoids abort)
 * 2. Includes retry logic for NS_BINDING_ABORTED errors (Firefox)
 * 3. Handles "Navigation canceled by policy check" errors (Safari)
 * 4. Checks if URL is already correct before failing
 */
declare function safeWaitForURL(page: Page, urlPattern: string | RegExp | ((url: URL) => boolean), options?: SafeWaitForURLOptions): Promise<void>;

declare function waitForPageLoad(page: Page): Promise<void>;
declare function closeWithEsc(page: Page): Promise<void>;
type StepFn = (title: string, fn: () => unknown) => unknown;
declare const test: any;
declare const retry: (action: () => Promise<void>, errorMessage: string, retryCount?: number) => Promise<void>;

declare const isJSON: (value: string) => boolean;

declare const logger: winston.Logger;

interface MailsacEmail {
    _id: string;
    from: Array<{
        address: string;
        name?: string;
    }>;
    to: Array<{
        address: string;
        name?: string;
    }>;
    subject: string;
    inbox: string;
    received: string;
    size: number;
    attachments: string[];
    ip: string;
    via: string;
    folder: string;
    labels: string[];
    read: boolean;
    rtls: boolean;
    originalInbox: string;
    spam: boolean;
}
declare class MailsacClient {
    private apiKey;
    private baseUrl;
    constructor(apiKey: string);
    /**
     * Get all emails for a specific inbox
     * @param inbox - The inbox address (e.g., 'test@mailsac.com' or just 'test')
     */
    getEmails(inbox: string): Promise<MailsacEmail[]>;
    /**
     * Get a specific email by ID
     * @param email - The email address
     * @param messageId - The ID of the email to fetch
     */
    getEmailById(email: string, messageId: string): Promise<string>;
    /**
     * Delete a specific email by ID
     * @param emailId - The ID of the email to delete
     */
    deleteEmail(emailId: string): Promise<any>;
}

declare class AuthFlowBuilder {
    flow: string;
    idp: string;
    authHost: string;
    constructor(flow?: string, idp?: string, authHost?: string);
    run(page: Page, step: StepFn, username: string, password: string, hostUrl: string, authUrl: string, postLoginUrlMatcher?: (url: URL) => boolean): Promise<void>;
    usernamePasswordFlow(page: Page, username: string, password: string, hostUrl: string, authUrl: string, postLoginUrlMatcher?: (url: URL) => boolean): Promise<void>;
    magicLinkFlow(page: Page): Promise<void>;
    ssoFlow(page: Page, username: string, password: string, hostUrl: string, authUrl: string): Promise<void>;
    directSsoFlow(page: Page, step: StepFn, username: string, password: string, hostUrl: string, authUrl: string): Promise<void>;
}

interface SignUpCredentials {
    email: string;
    password: string;
}
declare function signUpWithEmailAndPassword(page: Page, authHost: string, postSignUpUrl: string, credentials?: SignUpCredentials, alreadyInSignupPage?: boolean): Promise<void>;
declare function loginWithEmailAndPassword(page: Page, username: string, password: string, hostUrl: string, postLoginUrlMatcher?: (url: URL) => boolean): Promise<void>;
declare function loginWithMicrosoftIdp(page: Page, username: string, password: string): Promise<void>;
declare function canChatWithEmbedMentor(page: Page, openChatButton: Locator): Promise<void>;
declare function getMentorIdFromUrl(url: string): string | null;

interface AuthSetupConfig {
    /** The app's host URL (e.g., https://mentor.example.com) */
    hostUrl: string;
    /** The auth service host URL (e.g., https://auth.example.com) */
    authHost: string;
    /** App name used in the login redirect URL (e.g., 'mentor', 'skills') */
    appName: string;
    /** Function to match the post-login URL to confirm authentication succeeded */
    postLoginUrlMatcher: (url: URL) => boolean;
    /** Auth flow type. Defaults to reading AUTH_FLOW env var or 'username_password' */
    authFlow?: 'username_password' | 'magic_link' | 'sso' | 'direct_sso';
    /** Auth IDP name for SSO flows */
    authIdp?: string;
}
/**
 * Creates a Playwright setup test function for authentication.
 * Use this as the test body in your auth.setup.ts file:
 *
 * ```ts
 * import { test as setup } from '@iblai/iblai-js/playwright';
 * import { createAuthSetup } from '@iblai/iblai-js/playwright';
 *
 * setup('authenticate', createAuthSetup({
 *   hostUrl: process.env.MENTOR_NEXTJS_HOST || '',
 *   authHost: process.env.AUTH_HOST || '',
 *   appName: 'mentor',
 *   postLoginUrlMatcher: (url) => url.href.includes('/platform/'),
 * }));
 * ```
 */
declare function createAuthSetup(config: AuthSetupConfig): ({ browser, step }: {
    browser: any;
    step: any;
}, testInfo: any) => Promise<void>;

declare class CustomReporter implements Reporter {
    onBegin(config: FullConfig, suite: Suite): void;
    onTestBegin(test: TestCase): void;
    onTestEnd(test: TestCase, result: TestResult): void;
    onTimeout(timeout: number): void;
    onEnd(result: FullResult): Promise<{
        status?: FullResult['status'];
    } | undefined | void> | void;
    onStdOut(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void;
    onStdErr(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void;
}

/**
 * Wait for a page to be fully ready (DOM complete + brief delay for lazy rendering)
 */
declare function waitForPageReady(page: Page, timeout?: number): Promise<void>;
/**
 * Check if the current user is an admin by reading localStorage
 */
declare function checkAdminStatus(page: Page): Promise<boolean>;
/**
 * Wait for an element to be fully stable (attached, visible, not animating)
 */
declare function waitForElementStable(page: Page, locator: Locator, timeout?: number): Promise<Locator>;
/**
 * Click an element with retry logic and stability checks
 */
declare function reliableClick(page: Page, locator: Locator, timeout?: number, maxRetries?: number): Promise<void>;
/**
 * Fill an input element with retry logic, clearing first and verifying the value
 */
declare function reliableFill(page: Page, locator: Locator, value: string, timeout?: number, maxRetries?: number): Promise<void>;
/**
 * Wait for a dialog element to be visible and its content loaded
 */
declare function waitForDialogReady(page: Page, dialogLocator: Locator, timeout?: number): Promise<Locator>;
/**
 * Select a date from a calendar component, navigating months if needed
 */
declare function selectDateFromCalendar(page: Page, dialogLocator: Locator, targetDate: Date, timeout?: number): Promise<void>;
/**
 * Run axe-core accessibility checks against a page
 */
declare function expectNoAccessibilityViolations(page: Page): Promise<void>;
/**
 * Run axe-core accessibility checks against visible dialogs
 */
declare function expectNoAccessibilityViolationsOnDialogs(page: Page, rules?: RuleObject, exclude?: string[]): Promise<void>;

declare function inviteUserTest(page: Page, inviteModal: Locator): Promise<void>;
declare function navigateToAccountComponent(page: Page, profileBtn: Locator): Promise<any>;
declare function navigateToDataReports(page: Page): Promise<void>;
declare function shouldDisplayReportCards(page: Page, REPORT_CARDS: {
    name: string;
    ariaLabel: string;
    description: string;
    expectsCsvEditor: boolean;
}[]): Promise<void>;
declare function shouldOpenCSVEditorDialog(page: Page): Promise<void>;
declare function shouldDisplayCSVInEditableTableFormat(page: Page): Promise<void>;
declare function shouldAllowEditingCellValuesInCSVEditor(page: Page): Promise<void>;
declare function shouldAddNewRowWhenClickingAddRowButton(page: Page): Promise<void>;
declare function shouldSaveEditedCSVAndTriggerDownload(page: Page): Promise<void>;
declare function shouldCloseCSVEditorWithoutSavingWhenClickingCancel(page: Page): Promise<void>;
declare function shouldCloseCSVEditorWhenClickingCloseButton(page: Page): Promise<void>;
declare function shouldVerifyCSVEditorDialogAccessibility(page: Page): Promise<void>;
declare function shouldOpenCSVEditorForUserMetadataReport(page: Page): Promise<void>;
declare function shouldDirectlyDownloadChatHistoryReportWithoutCSVEditor(page: Page): Promise<void>;
declare function shouldDisableOtherDownloadButtonsWhileGeneratingReport(page: Page): Promise<void>;
declare function shouldShowCombiningReportsDialog(page: Page): Promise<void>;
declare function shouldCancelCombiningReports(page: Page): Promise<void>;
declare function shouldHaveCombinedReportDataTestIds(page: Page): Promise<void>;
declare function shouldCombineRecommendationReports(page: Page): Promise<void>;

type AuthFlowType = 'username_password' | 'magic_link' | 'sso' | 'direct_sso';
interface EnvConfig {
    skillHost: string;
    authHost: string;
    analyticsHost: string;
    mentorHost: string;
    mentorNextjsHost: string;
    authNextjsHost: string;
    playwrightUsername: string;
    playwrightPassword: string;
    inviteUsername: string;
    inviteUserPassword: string;
    authFlow: AuthFlowType;
    authIdp: string;
    enableStripeTest: boolean;
    iblMentorDisabledTabs: string;
    embedUrl: string;
    wcagRange: string;
}
/**
 * Create an environment configuration object from process.env with optional overrides.
 * Each app can call this with their specific defaults.
 */
declare function createEnvConfig(overrides?: Partial<EnvConfig>): EnvConfig;

interface PlatformConfig {
    /** Platform name used in project naming (e.g., 'mentornextjs', 'skills') */
    name: string;
    /** Devices to test on. Defaults to all 4 desktop browsers */
    devices?: string[];
    /** Dependencies for this platform (e.g., ['setup']) */
    dependencies?: string[];
    /** Additional test file patterns to match */
    otherTestMatch?: string[];
    /** Test files to ignore */
    testIgnore?: string[];
}
interface CreatePlaywrightConfigOptions {
    /** Directory containing test files (relative to config file) */
    testDir?: string;
    /** Devices to use across all platforms. Defaults to Chrome, Firefox, Safari, Edge */
    devices?: string[];
    /** Platform configurations */
    platforms: PlatformConfig[];
    /** Path to custom reporter module (relative to config file). Defaults to './custom-reporter' */
    customReporterPath?: string;
    /** Additional cleanup or post-test projects */
    extraProjects?: Array<{
        name: string;
        devices?: string[];
        dependencies: string[];
        testMatch: string[];
    }>;
}
/** Extract browser key from device name (e.g., 'Desktop Chrome' -> 'chrome') */
declare function getBrowserKey(deviceName: string): string;
/**
 * Generate per-browser setup projects for Playwright authentication.
 * Each browser gets its own auth setup project (setup-chrome, setup-firefox, etc.)
 */
declare function generateBrowserSetupProjects(devicesToUse: string[]): {
    name: string;
    testMatch: RegExp;
    use: any;
}[];
/**
 * Generate a Playwright project config for a platform + device combination.
 */
declare function generateProjectConfig(platform: string, deviceName: string, dependencies?: string[], otherTestMatch?: string[], testIgnoreMatch?: string[]): {
    name: string;
    testMatch: string[];
    use: any;
    dependencies: string[];
    testIgnore: string[];
};
/**
 * Create a complete Playwright configuration for an IBL.ai application.
 *
 * Usage:
 * ```ts
 * import { createPlaywrightConfig } from '@iblai/iblai-js/playwright';
 *
 * export default createPlaywrightConfig({
 *   platforms: [
 *     { name: 'skills', dependencies: ['setup'], otherTestMatch: ['**skills/*\/*.spec.ts'] },
 *   ],
 * });
 * ```
 */
declare function createPlaywrightConfig(options: CreatePlaywrightConfigOptions): PlaywrightTestConfig;

export { AuthFlowBuilder, CustomReporter, MailsacClient, canChatWithEmbedMentor, checkAdminStatus, closeWithEsc, createAuthSetup, createEnvConfig, createPlaywrightConfig, expectNoAccessibilityViolations, expectNoAccessibilityViolationsOnDialogs, generateBrowserSetupProjects, generateProjectConfig, getBrowserKey, getMentorIdFromUrl, inviteUserTest, isFirefox, isJSON, logger, loginWithEmailAndPassword, loginWithMicrosoftIdp, navigateToAccountComponent, navigateToDataReports, reliableClick, reliableFill, retry, safeWaitForURL, selectDateFromCalendar, shouldAddNewRowWhenClickingAddRowButton, shouldAllowEditingCellValuesInCSVEditor, shouldCancelCombiningReports, shouldCloseCSVEditorWhenClickingCloseButton, shouldCloseCSVEditorWithoutSavingWhenClickingCancel, shouldCombineRecommendationReports, shouldDirectlyDownloadChatHistoryReportWithoutCSVEditor, shouldDisableOtherDownloadButtonsWhileGeneratingReport, shouldDisplayCSVInEditableTableFormat, shouldDisplayReportCards, shouldHaveCombinedReportDataTestIds, shouldOpenCSVEditorDialog, shouldOpenCSVEditorForUserMetadataReport, shouldSaveEditedCSVAndTriggerDownload, shouldShowCombiningReportsDialog, shouldVerifyCSVEditorDialogAccessibility, signUpWithEmailAndPassword, test, waitForDialogReady, waitForElementStable, waitForPageLoad, waitForPageReady };
export type { AuthFlowType, AuthSetupConfig, CreatePlaywrightConfigOptions, EnvConfig, PlatformConfig, SafeWaitForURLOptions, SignUpCredentials, StepFn };
