import type { CertificateDto } from "@mmapp/contracts/certificates"

export type RosCertificateRow = Record<string, string | undefined>

function parseRosDate(raw: string | undefined): Date | null {
  if (!raw?.trim()) return null
  const d = new Date(raw)
  return Number.isNaN(d.getTime()) ? null : d
}

function fmtDate(d: Date): string {
  return d.toISOString().slice(0, 10)
}

function parseSans(raw: string | undefined): string[] {
  if (!raw?.trim()) return []
  return raw
    .split(",")
    .map((part) => part.trim())
    .map((part) => {
      const m = part.match(/^(?:DNS|IP|email):(.+)$/i)
      return (m?.[1] ?? part).trim()
    })
    .filter(Boolean)
}

function parseUsage(raw: string | undefined): CertificateDto["usage"] {
  if (!raw?.trim()) return []
  const out = new Set<CertificateDto["usage"][number]>()
  for (const part of raw.split(",")) {
    const token = part.trim().toLowerCase()
    if (token === "tls-server") out.add("server")
    else if (token === "tls-client") out.add("client")
    else if (token === "key-cert-sign") out.add("ca")
    else if (token === "crl-sign") out.add("crl-sign")
  }
  return [...out]
}

function parseFlags(raw: string | undefined): { revoked: boolean; expired: boolean } {
  const flags = (raw ?? "").toUpperCase()
  return {
    revoked: flags.includes("R"),
    expired: flags.includes("E"),
  }
}

export function mapRosCertificateRow(
  serverId: number,
  serverName: string,
  row: RosCertificateRow,
): CertificateDto | null {
  const name = (row.name ?? "").trim()
  if (!name) return null

  const rosId = (row[".id"] ?? "").trim()
  const fingerprint = (row.fingerprint ?? "").trim()
  const serialNumber = (row["serial-number"] ?? "").trim()
  const stableId = rosId || fingerprint || serialNumber || name

  const { revoked, expired: expiredFlag } = parseFlags(row.flags)
  const validFrom = parseRosDate(row["invalid-before"])
  const validUntil = parseRosDate(row["invalid-after"])
  const now = new Date()
  const daysLeft = validUntil
    ? Math.ceil((validUntil.getTime() - now.getTime()) / 86_400_000)
    : 0

  let status: CertificateDto["status"] = "valid"
  if (revoked) status = "revoked"
  else if (expiredFlag || (validUntil != null && validUntil.getTime() < now.getTime())) status = "expired"

  const keySize = Number.parseInt(String(row["key-size"] ?? "0"), 10)

  return {
    id: `${serverId}:${stableId}`,
    name,
    serverId: String(serverId),
    serverName,
    commonName: (row["common-name"] ?? name).trim(),
    sans: parseSans(row["subject-alt-name"]),
    issuedBy: (row.issuer ?? "—").trim() || "—",
    validFrom: validFrom ? fmtDate(validFrom) : "—",
    validUntil: validUntil ? fmtDate(validUntil) : "—",
    daysLeft,
    keySize: Number.isFinite(keySize) ? keySize : 0,
    usage: parseUsage(row["key-usage"]),
    trusted: row.trusted === "true",
    status,
    acmeStatus: row["acme-status"]?.trim() || undefined,
  }
}

export function mapRosCertificates(
  serverId: number,
  serverName: string,
  rows: RosCertificateRow[],
): CertificateDto[] {
  const seen = new Set<string>()
  return rows
    .map((row) => mapRosCertificateRow(serverId, serverName, row))
    .filter((row): row is CertificateDto => row != null)
    .map((cert, index) => {
      if (!seen.has(cert.id)) {
        seen.add(cert.id)
        return cert
      }
      const uniqueId = `${cert.id}#${index}`
      seen.add(uniqueId)
      return { ...cert, id: uniqueId }
    })
}
