import { Linking } from 'react-native';
import { normalizePhoneInput } from './phone';
import { openCallUi } from './callUiNav';

interface PendingCall {
  phone: string;
  clientId?: number;
  clientName?: string;
  startedAt: number;
}

let pending: PendingCall | null = null;

/** Skip auto-open while user is already on a journal for this number. */
let journalLockPhone = '';
let journalLockUntil = 0;

/** Where to go after saving / closing journal (e.g. `/visit/123`) — survives dialer deep-link. */
let journalReturnTo: string | null = null;

export function setJournalReturnTo(path: string | null | undefined): void {
  journalReturnTo = path?.trim() ? path.trim() : null;
}

export function peekJournalReturnTo(): string | null {
  return journalReturnTo;
}

export function consumeJournalReturnTo(): string | null {
  const path = journalReturnTo;
  journalReturnTo = null;
  return path;
}

/** Call when post-call is opened manually so return-from-dialer does not stack another form. */
export function lockCallWatchForPhone(phone: string, ms = 120_000): void {
  const n = normalizePhoneInput(phone);
  if (!n) return;
  journalLockPhone = n;
  journalLockUntil = Date.now() + ms;
}

export function isCallWatchJournalLocked(phone: string): boolean {
  if (!phone || Date.now() > journalLockUntil) return false;
  return normalizePhoneInput(phone) === journalLockPhone;
}

/** E.164 dial URI with leading + (international). */
export function telUri(phoneDigits: string): string {
  const d = phoneDigits.replace(/\D/g, '');
  return d ? `tel:+${d}` : 'tel:';
}

/**
 * Open the native dialer.
 * @param track — if true, AppState will open post-call on return (legacy path).
 */
export async function dialPhone(
  phone: string,
  opts?: { track?: boolean; clientId?: number; clientName?: string },
): Promise<string | null> {
  const normalized = normalizePhoneInput(phone);
  if (!normalized) return null;
  if (opts?.track) {
    pending = {
      phone: normalized,
      clientId: opts.clientId,
      clientName: opts.clientName,
      startedAt: Date.now(),
    };
  }
  try {
    await Linking.openURL(telUri(normalized));
  } catch {
    if (opts?.track) pending = null;
    return null;
  }
  return normalized;
}

/** @deprecated prefer openCallReportAndDial — kept for callers that only dial */
export async function startTrackedCall(phone: string, clientId?: number): Promise<void> {
  await dialPhone(phone, { track: true, clientId });
}

/**
 * CRM-style: open compte-rendu modal, optionally dial with +.
 * Form is already open — dial without AppState track (native call-watch covers return).
 */
export async function openCallReportAndDial(opts: {
  phone: string;
  clientId?: number | null;
  clientName?: string | null;
  threadId?: number | null;
  dial?: boolean;
  /** Sortant = dial/call button, Entrant = incoming, omit = journaliser (user picks). */
  callType?: 'Sortant' | 'Entrant' | 'Rappel';
  mode?: 'dial' | 'incoming' | 'journal';
  /** After save/close, return here instead of Accueil (e.g. `/visit/12`). */
  returnTo?: string | null;
}): Promise<void> {
  const normalized = normalizePhoneInput(opts.phone);
  const mode = opts.mode ?? (opts.dial === false && !opts.callType ? 'journal' : opts.callType === 'Entrant' ? 'incoming' : 'dial');
  const params: Record<string, string> = {
    mode,
  };
  if (opts.callType) params.callType = opts.callType;
  else if (mode === 'dial') params.callType = 'Sortant';
  else if (mode === 'incoming') params.callType = 'Entrant';
  if (normalized) params.phone = normalized;
  if (opts.clientId) params.clientId = String(opts.clientId);
  if (opts.clientName?.trim()) params.clientName = opts.clientName.trim();
  if (opts.threadId) params.threadId = String(opts.threadId);
  if (opts.returnTo?.trim()) {
    params.returnTo = opts.returnTo.trim();
    setJournalReturnTo(opts.returnTo.trim());
  }

  if (normalized) lockCallWatchForPhone(normalized);
  openCallUi('post', params);

  if (opts.dial !== false && normalized && mode !== 'journal') {
    setTimeout(() => {
      void dialPhone(normalized, { track: false, clientId: opts.clientId ?? undefined });
    }, 350);
  }
}

/**
 * Returns the pending call once, if the user spent at least `minMs` outside the app.
 */
export function consumePendingCall(minMs = 5000): PendingCall | null {
  if (!pending) return null;
  const elapsed = Date.now() - pending.startedAt;
  const call = pending;
  pending = null;
  return elapsed >= minMs ? call : null;
}

export function hasPendingCall(): boolean {
  return pending !== null;
}
