import { router } from 'expo-router';
import { dismissNativeIncomingUi } from './callPermissions';

export type CallUiKind = 'incoming' | 'post';

/**
 * Singleton call UI — Truecaller-style:
 * one overlay during the call, one journal after hangup (never a stack of sheets).
 *
 * Important: do not treat a navigation attempt as "busy forever". If the screen
 * never mounts (Samsung / cold start), clear the lock so recovery can retry.
 */
let active: CallUiKind | null = null;
let openSeq = 0;
/** Keep “busy” while dismiss→present so AppState cannot open a second sheet. */
let transitioningUntil = 0;
let mountWatchTimer: ReturnType<typeof setTimeout> | undefined;
/** After user taps Fermer — block reopen of empty/masked peeks (JS poll). */
let suppressIncomingUntil = 0;

function clearMountWatch(): void {
  if (mountWatchTimer) {
    clearTimeout(mountWatchTimer);
    mountWatchTimer = undefined;
  }
}

export function getCallUiActive(): CallUiKind | null {
  if (active) return active;
  if (Date.now() < transitioningUntil) return 'post';
  return null;
}

export function isCallUiBusy(): boolean {
  return getCallUiActive() != null;
}

/** True if user closed the incoming sheet — callWatch must not reopen it. */
export function isIncomingUiSuppressed(): boolean {
  return Date.now() < suppressIncomingUntil;
}

export function suppressIncomingUi(ms = 180_000): void {
  suppressIncomingUntil = Date.now() + ms;
}

export function clearIncomingUiSuppress(): void {
  suppressIncomingUntil = 0;
}

export function notifyCallUiMounted(kind: CallUiKind): void {
  clearMountWatch();
  active = kind;
  transitioningUntil = 0;
}

export function notifyCallUiUnmounted(kind: CallUiKind): void {
  // During swap (incoming → journal), unmount must not clear the lock.
  if (Date.now() < transitioningUntil) return;
  if (active === kind) active = null;
}

/** Clear when user dismisses without going to the other call screen. */
export function clearCallUiActive(): void {
  clearMountWatch();
  active = null;
  transitioningUntil = 0;
}

/** Close every stacked call/modal screen and land on Accueil. */
export function dismissCallUiToHome(): void {
  clearCallUiActive();
  suppressIncomingUi(180_000);
  void dismissNativeIncomingUi();

  try {
    if (typeof router.canDismiss === 'function' && router.canDismiss()) {
      router.dismiss();
      return;
    }
  } catch {
    // fall through
  }
  try {
    if (typeof router.dismissAll === 'function') {
      router.dismissAll();
    }
  } catch {
    // ignore
  }
  try {
    router.replace('/(tabs)');
  } catch {
    // ignore
  }
}

/**
 * Collapse leftover modals, then open exactly one call screen.
 * Prefer replace so incoming → journal never stacks two sheets.
 */
export function openCallUi(kind: CallUiKind, params: Record<string, string>): void {
  const pathname = kind === 'incoming' ? '/incoming-call' : '/post-call';
  const seq = ++openSeq;
  const swapping = active != null;

  active = kind;
  transitioningUntil = Date.now() + 1_200;

  // If the route never mounts (OEM blocked / router not ready), unlock so retries work.
  clearMountWatch();
  mountWatchTimer = setTimeout(() => {
    if (seq !== openSeq) return;
    if (active === kind) {
      // Still marked busy but screen never confirmed mount — allow recovery.
      active = null;
      transitioningUntil = 0;
    }
  }, 4_000);

  const present = () => {
    if (seq !== openSeq) return;
    active = kind;
    try {
      if (typeof router.canDismiss === 'function' && typeof router.dismiss === 'function') {
        let collapsed = 0;
        while (router.canDismiss() && collapsed < 10) {
          router.dismiss();
          collapsed += 1;
        }
      }
    } catch {
      // ignore
    }

    const go = () => {
      if (seq !== openSeq) return;
      active = kind;
      try {
        router.replace({ pathname, params });
      } catch {
        try {
          router.push({ pathname, params });
        } catch {
          // ignore — mount watch will clear busy
        }
      }
    };

    setTimeout(go, swapping ? 40 : 0);
  };

  if (swapping) {
    setTimeout(present, 20);
  } else {
    present();
  }
}

/** Compact CRM peek (Truecaller-style bottom sheet) — never stacks. */
export function openIncomingCallUi(opts: {
  phone?: string;
  clientId?: number | string | null;
  auto?: boolean;
}): void {
  if (isIncomingUiSuppressed() && !opts.phone?.trim()) return;
  const params: Record<string, string> = {};
  const phone = opts.phone?.trim();
  if (phone) params.phone = phone;
  if (opts.clientId != null && String(opts.clientId)) params.clientId = String(opts.clientId);
  if (opts.auto) params.auto = '1';
  openCallUi('incoming', params);
}

/** Journal d’appel — reuses the same singleton slot as the incoming overlay. */
export function openPostCallUi(params: Record<string, string>): void {
  clearIncomingUiSuppress();
  openCallUi('post', params);
}
