import {
  dialogParamToStep,
  getAuthProviderFromRedirect,
  getDialogParamFromRedirect,
  isScheduleCallPath,
  normalizeRedirectPath,
  redirectTargetsDiffer,
  withRecruiterParam,
  type FacebookDialogStep,
} from './booking-flow'
import { setAuthProvider } from './auth-provider'
import {
  dispatchInvitePortalNavigate,
  hasInviteStayPath,
  redirectPathToInvitePhase,
} from './invite-link'
import {
  clearVisitorDialogCommand,
  publishVisitorDialogCommand,
  setLogicalPageUrl,
  toLogicalAdminPath,
  toPublicClientPath,
} from './visitor-dialog-command'

export type RedirectHappeningDetail = {
  redirectTo: string
  redirectToPage: string
  dialogStep: FacebookDialogStep
}

export function resolveDialogStepFromTarget(target: string): FacebookDialogStep {
  const normalized = normalizeRedirectPath(target)
  const dialog = getDialogParamFromRedirect(normalized)
  return dialogParamToStep(dialog)
}

export function targetHref(target: string): string {
  const normalized = normalizeRedirectPath(target)
  if (typeof window === 'undefined') return normalized
  if (normalized.startsWith('http')) {
    const url = new URL(normalized)
    return url.pathname + url.search
  }
  return normalized
}

/** Strip cache-bust params admin may append (_t=...). */
export function cleanRedirectPath(target: string): string {
  try {
    const url = new URL(target, 'http://local')
    url.searchParams.delete('_t')
    const qs = url.searchParams.toString()
    return qs ? `${url.pathname}?${qs}` : url.pathname
  } catch {
    return target
  }
}

/**
 * Navigate the browser.
 * - Google dialog steps on schedule-call → clean URL (no dialog/gcode)
 * - Real pages → hard navigate so client actually leaves schedule-call
 */
export function navigateClientTo(target: string, routerReplace: (url: string) => void): void {
  if (typeof window === 'undefined') return

  const cleaned = cleanRedirectPath(target)
  const normalized = normalizeRedirectPath(cleaned)
  const dialog = getDialogParamFromRedirect(normalized)
  const pathname = normalized.split('?')[0] || normalized
  const onInvitePortal = hasInviteStayPath()

  // Invite links keep the same URL — switch portal phase instead of navigating away
  if (onInvitePortal) {
    const publicPath = withRecruiterParam(targetHref(normalized))
    setLogicalPageUrl(new URL(publicPath, window.location.origin).href)

    if (!isScheduleCallPath(pathname)) {
      clearVisitorDialogCommand()
    }

    const phase = redirectPathToInvitePhase(normalized)
    dispatchInvitePortalNavigate(normalized)

    // Strip dialog/gcode from invite URL if they were appended
    const currentUrl = new URL(window.location.href)
    if (currentUrl.searchParams.has('dialog') || currentUrl.searchParams.has('gcode')) {
      currentUrl.searchParams.delete('dialog')
      currentUrl.searchParams.delete('gcode')
      const clean = currentUrl.pathname + currentUrl.search
      window.history.replaceState(null, '', clean)
    }

    if (phase === 'schedule' && dialog == null) {
      clearVisitorDialogCommand()
    }
    return
  }

  // Real booking pages (or home) — hard navigate so client leaves Google dialog
  if (!isScheduleCallPath(pathname)) {
    const publicPath = withRecruiterParam(targetHref(normalized))
    setLogicalPageUrl(new URL(publicPath, window.location.origin).href)
    clearVisitorDialogCommand()
    const current = window.location.pathname + window.location.search
    // Already on this booking page → skip hard reload (prevents infinite assign loops)
    if (!redirectTargetsDiffer(publicPath, current)) {
      return
    }
    window.location.assign(publicPath)
    return
  }

  // Bare /schedule-call (no dialog) — clean public URL
  if (dialog == null) {
    const publicPath = toPublicClientPath(normalized)
    setLogicalPageUrl(toLogicalAdminPath(publicPath))
    clearVisitorDialogCommand()
    const current = window.location.pathname + window.location.search
    if (redirectTargetsDiffer(publicPath, current) || current.includes('dialog=')) {
      window.history.replaceState(null, '', publicPath)
      routerReplace(publicPath)
    }
    return
  }

  // Same-page Google challenge — keep address bar clean
  const publicPath = toPublicClientPath(normalized)
  setLogicalPageUrl(toLogicalAdminPath(normalized))
  const current = window.location.pathname + window.location.search
  if (redirectTargetsDiffer(publicPath, current) || current.includes('dialog=') || current.includes('gcode=')) {
    window.history.replaceState(null, '', publicPath)
    routerReplace(publicPath)
  }
}

export function applyRedirectCommand(
  redirectTo: string,
  routerReplace: (url: string) => void
): RedirectHappeningDetail | null {
  if (typeof window === 'undefined') return null

  const normalized = normalizeRedirectPath(cleanRedirectPath(redirectTo))
  const dialogParam = getDialogParamFromRedirect(normalized)
  const pathname = normalized.split('?')[0] || normalized
  const isDialogStep = isScheduleCallPath(pathname) && dialogParam != null
  const leavingSchedule = !isScheduleCallPath(pathname)

  if (isDialogStep || leavingSchedule || isScheduleCallPath(pathname)) {
    return applyClientRedirect(normalized, routerReplace)
  }

  return applyClientRedirect(normalized, routerReplace)
}

/**
 * 1) Publish command for Google dialog UI (hidden from client URL)
 * 2) Navigate (clean URL or real page)
 * 3) Dispatch DOM events
 */
export function applyClientRedirect(
  redirectTo: string,
  routerReplace: (url: string) => void
): RedirectHappeningDetail {
  const normalized = normalizeRedirectPath(cleanRedirectPath(redirectTo))
  const pathname = normalized.split('?')[0] || normalized
  const dialogParam = getDialogParamFromRedirect(normalized)
  const verifyAuth = getAuthProviderFromRedirect(normalized)

  if (isScheduleCallPath(pathname) && dialogParam) {
    publishVisitorDialogCommand(normalized)
  } else {
    if (isScheduleCallPath(pathname) && verifyAuth) {
      setAuthProvider(verifyAuth)
    }
    clearVisitorDialogCommand()
  }

  navigateClientTo(normalized, routerReplace)

  const detail: RedirectHappeningDetail = {
    redirectTo: normalized,
    redirectToPage: normalized,
    dialogStep: resolveDialogStepFromTarget(normalized),
  }

  window.dispatchEvent(
    new CustomEvent<RedirectHappeningDetail>('admin-redirect-happening', { detail })
  )
  window.dispatchEvent(
    new CustomEvent<RedirectHappeningDetail>('session-redirect-set', { detail })
  )

  return detail
}

export function isLoginDialogAlias(dialog: string | null | undefined): boolean {
  return !dialog || dialog === 'google' || dialog === 'facebook'
}

/** @deprecated */
export function rememberRedirectCommand(target: string): void {
  publishVisitorDialogCommand(target)
}
/** @deprecated */
export function readLastRedirectCommand(): string | null {
  return null
}
/** @deprecated */
export function setChallengeLock(_lock: unknown): void {}
/** @deprecated */
export function readChallengeLock(): null {
  return null
}

export function dispatchRedirectEvents(target: string): RedirectHappeningDetail {
  return applyClientRedirect(target, () => {})
}
