// OpenSafari MCP Server — Public API
// iOS Safari automation via Xcode Simulator + WebKit Remote Debugging Protocol

import { MCPServer } from './mcp-server';
import { registerAllTools } from './tools';

// Core server
export { MCPServer, getWebKitClient, setWebKitClient } from './mcp-server';
export { getSessionManager, SessionManager } from './session-manager';
export type { SimulatorInfo, WorkerInfo } from './session-manager';
export type { MCPServerOptions } from './mcp-server';

// Tool registration
export { registerAllTools, setWorkflowEngine, setCrossViewportCapture, setScenarioRunner, setBarrier, setCrossDeviceAssert, setCompareDevicesCapture, setCompareDevicesBatchExecutor, setHybridQAEngine } from './tools';

// Hybrid QA
export { HybridQAEngine } from './orchestration/hybrid-qa';
export type { HybridQAOptions, HybridQAResult, PageScanResult, VerifiedIssue } from './orchestration/hybrid-qa';

// WebKit client
export { WebKitClient } from './webkit/client';
export type { WebKitClientOptions, WebKitTarget } from './webkit/client';

// Simulator
export { SimulatorManager } from './simulator';
export { SimulatorPool } from './simulator/pool';
export { TabPool } from './simulator/tab-pool';
export type { TabInfo, TabPoolOptions } from './simulator/tab-pool';
export { TabClient } from './simulator/tab-client';
export type { PooledSimulator, SimulatorPoolOptions } from './simulator/pool';
export { WebInspectorProxy, getSharedProxy } from './simulator/proxy';
export type { ProxyOptions } from './simulator/proxy';
export { DEVICE_PRESETS } from './simulator/presets';

// Auth
export { AuthManager } from './auth';
export type { AuthProfile, ExpiryInfo } from './auth';

// Orchestration
export { SimulatorWorkflowEngine } from './orchestration/workflow-engine';
export { ScenarioRunner } from './orchestration/scenario-runner';
export { CrossViewportCapture } from './comparison/cross-viewport';

// Comparison Engines
export { VisualDiffEngine } from './comparison/visual-diff';
export type { VisualDiffOptions, VisualDiffResult, PairwiseComparisonMatrix, BoundingBox } from './comparison/visual-diff';
export { DOMDiffEngine, DOM_SNAPSHOT_SCRIPT } from './comparison/dom-diff';
export type { DOMDiffOptions, DOMDiffResult, DOMDifference, DOMSnapshot, DOMElementSnapshot } from './comparison/dom-diff';

// Configuration
export { getGlobalConfig, setGlobalConfig, resetGlobalConfig } from './config/global';
export type { OpenSafariConfig } from './config/global';

// Types
export type { BrowserBackend, NavigateOptions, NavigateResult, ElementInfo, Cookie } from './types/browser-backend';

// Native app backend (stub)
export { NativeAppClient } from './native-app/client';
export type { NativeAppBackend, AccessibilityElement, AppInfo } from './types/native-app-backend';
export type { AutomationBackend, AutomationBackendBase, BackendType } from './types/automation-backend';

// Convenience factory
export async function createServer(options?: {
  transport?: 'stdio' | 'http';
  port?: number;
  host?: string;
  authToken?: string;
  httpInsecure?: boolean;
  allowedOrigins?: string[];
  httpHighRiskTools?: boolean;
  allTools?: boolean;
}): Promise<MCPServer> {
  const server = new MCPServer();
  registerAllTools(server);

  // Rehydrate the in-memory SessionManager from any simulators that were
  // booted before this server started. Without this, an MCP client
  // reconnect leaves SessionManager empty and the LLM tries to re-boot
  // the simulator it's already talking to. Best-effort: missing simctl,
  // permissions issues, or weird states fall through without aborting
  // server startup.
  try {
    // Late-bound imports so this module can stay free of a static
    // dependency on the simulator/* sources at module-load time (helps
    // smaller `import { ... } from '.'` bundles).
    const { getSessionManager } = await import('./session-manager');
    const { getDefaultSimulatorManager } = await import('./simulator');
    const { DEVICE_PRESETS } = await import('./simulator/presets');
    const presetLookup = (name: string) => {
      const entry = Object.values(DEVICE_PRESETS).find((p) => p.name === name);
      return entry ? { w: entry.w, h: entry.h } : undefined;
    };
    const result = await getSessionManager().rehydrateFromSimctl(
      getDefaultSimulatorManager(),
      { presetLookup },
    );
    if (result.rehydrated.length > 0) {
      console.error(
        `[OpenSafari] Rehydrated ${result.rehydrated.length} simulator(s) from simctl: ${result.rehydrated.join(', ')}`,
      );
    }
  } catch (err) {
    console.error(
      `[OpenSafari] SessionManager rehydrate skipped: ${err instanceof Error ? err.message : String(err)}`,
    );
  }

  if (options?.allTools) {
    server.setTier(3);
  } else if (process.env.OPENSAFARI_TOOL_TIER) {
    const envTier = parseInt(process.env.OPENSAFARI_TOOL_TIER, 10);
    if (envTier === 1 || envTier === 2 || envTier === 3) {
      server.setTier(envTier);
    } else {
      console.error(`[OpenSafari] Warning: OPENSAFARI_TOOL_TIER=${process.env.OPENSAFARI_TOOL_TIER} is invalid (must be 1, 2, or 3). Using default tier.`);
    }
  }
  await server.start({
    transport: options?.transport ?? 'stdio',
    port: options?.port,
    host: options?.host,
    authToken: options?.authToken,
    httpInsecure: options?.httpInsecure,
    allowedOrigins: options?.allowedOrigins,
    httpHighRiskTools: options?.httpHighRiskTools,
  });
  return server;
}
