/**
 * @teres/iframe-bridge
 * Penpal-based utilities for host ↔ iframe communication,
 * plus minimal helpers for embed detection and path conversion.
 */
import { connectToChild, connectToParent } from 'penpal';

// Penpal RPC API definitions
export interface HostApi {
  navigate: (to: string) => void;
  close: () => void;
  agentReady?: (payload?: any) => void;
}

export interface ChildApi {
  navigate?: (to: string) => void;
  close?: () => void;
  ready?: (payload?: any) => void;
}

// Unified logger for debugging host/child interactions
const LOG_PREFIX = '[@teres/iframe-bridge]';
function log(...args: any[]) {
  try {
    // eslint-disable-next-line no-console
    console.log(LOG_PREFIX, ...args);
  } catch {}
}

function safePathname(): string {
  try {
    const p = window.location?.pathname || '';
    log('safePathname()', p);
    return p;
  } catch {
    log('safePathname() error, return empty pathname');
    return '';
  }
}

function isInIframe(): boolean {
  try {
    const inIframe = window.self !== window.top;
    log('isInIframe()', inIframe);
    return inIframe;
  } catch {
    // Cross-origin access throws, treat as embedded
    log('isInIframe() cross-origin error, treat as embedded');
    return true;
  }
}

export function isEmbedded(): boolean {
  const path = safePathname();
  const inIframe = isInIframe();
  const embedded = path.includes('/route-ragflow') || inIframe;
  log('isEmbedded()', { path, inIframe, embedded });
  return embedded;
}

/** Add "/ragflow" prefix when targeting host routes. */
export function toHostPath(to: string): string {
  const normalized = to.startsWith('/') ? to : `/${to}`;
  const target = normalized.startsWith('/route-ragflow') ? normalized : `/ragflow${normalized}`;
  log('toHostPath()', { input: to, normalized, target });
  return target;
}

/** Remove leading "/route-ragflow" prefix when targeting child routes. */
export function toChildPath(to: string): string {
  const target = to.replace(/^\/route-ragflow/, '') || '/';
  log('toChildPath()', { input: to, target });
  return target;
}

// Cached Penpal connections
let clientHostApiPromise: Promise<HostApi> | null = null;

/** Create a Penpal connection from child to parent and cache the Host API. */
export function getClientHostApi(options?: { parentOrigin?: string }): Promise<HostApi> {
  if (!isEmbedded()) {
    log('getClientHostApi() aborted: not embedded');
    return Promise.reject(new Error('Not embedded'));
  }
  if (!clientHostApiPromise) {
    const parentOrigin = options?.parentOrigin ?? window.location.origin;
    log('getClientHostApi() connecting to parent', { parentOrigin });
    clientHostApiPromise = connectToParent<HostApi>({ parentOrigin }).promise.then((host) => {
      log('getClientHostApi() connected', {
        hasNavigate: typeof host.navigate === 'function',
        hasClose: typeof host.close === 'function',
      });
      return host;
    });
  }
  return clientHostApiPromise;
}

export async function clientNavigate(to: string): Promise<void> {
  log('clientNavigate() begin', { to });
  const host = await getClientHostApi();
  await host.navigate(to);
  log('clientNavigate() done', { to });
}

export async function clientClose(): Promise<void> {
  log('clientClose() begin');
  const host = await getClientHostApi();
  log('clientClose() host api', {
    hasClose: typeof host.close === 'function',
  });
  await host.close();
  log('clientClose() done');
}

export async function clientReady(payload?: any): Promise<void> {
  log('clientReady() begin', { payload });
  const host = await getClientHostApi();
  const agentReady =  host.agentReady;
  const hasAgentReady = typeof agentReady === 'function';
  log('clientReady() host agentReady', { hasAgentReady });
  if (hasAgentReady) await agentReady!(payload);
  log('clientReady() done');
}

/** Establish Penpal host bridge bound to an iframe and expose Host API to child. */
export function createPenpalHostBridge(params: {
  iframe: HTMLIFrameElement;
  origin?: string;
  methods: HostApi;
}) {
  const childOrigin = params.origin ?? window.location.origin;
  log('createPenpalHostBridge() start', { childOrigin });
  const connection = connectToChild<ChildApi>({ iframe: params.iframe, childOrigin, methods: params.methods as any });
  connection.promise.then(() => log('createPenpalHostBridge() child connected')).catch((err) => log('createPenpalHostBridge() connect error', err));
  return {
    child: connection.promise,
    destroy: () => {
      log('createPenpalHostBridge() destroy');
      return connection.destroy?.();
    },
  };
}

// Provide a default export with all APIs to maximize compatibility with bundlers
// that prefer default-only federation or mis-handle named ESM exports in dev.
const bridge = {
  isEmbedded,
  toHostPath,
  toChildPath,
  getClientHostApi,
  clientNavigate,
  clientClose,
  clientReady,
  createPenpalHostBridge,
};

export default bridge;
