import type { TipTapJSON } from "@/lib/drive/richtext-import"
import type { DocsTableBorder } from "@/lib/drive/docs-table-types"

const BORDER_STYLES = new Set([
  "single",
  "dashed",
  "dotted",
  "double",
  "dotDash",
  "dotDotDash",
  "none",
])

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value)
}

function parseCssBorderValue(value: string): DocsTableBorder | null {
  const trimmed = value.trim()
  if (!trimmed || trimmed === "none" || trimmed === "0") return null
  const parts = trimmed.split(/\s+/)
  if (parts.length < 2) return null
  const size = parseFloat(parts[0] ?? "")
  const styleToken = parts[1] ?? "solid"
  const color = parts.slice(2).join(" ") || "#000000"
  const style = styleToken === "solid" ? "single" : styleToken
  return {
    size: Number.isFinite(size) ? Math.max(1, Math.round(size * 8)) : 8,
    style,
    color,
  }
}

/** Normalize border attrs for @docen/export-docx (DOCX Border objects). */
export function normalizeTableBorderForExport(
  border: unknown
): DocsTableBorder | null {
  if (!border) return null
  if (typeof border === "string") return parseCssBorderValue(border)

  if (!isRecord(border)) return null

  const styleRaw = typeof border.style === "string" ? border.style : "single"
  const style = styleRaw === "solid" ? "single" : styleRaw
  if (style === "none" || style === "nil") return null

  const color =
    typeof border.color === "string" && border.color
      ? border.color
      : "#000000"

  const size =
    typeof border.size === "number" && Number.isFinite(border.size)
      ? border.size
      : 8

  const normalized: DocsTableBorder = {
    size,
    style: BORDER_STYLES.has(style) ? style : "single",
    color,
  }

  if (typeof border.space === "number" && Number.isFinite(border.space)) {
    normalized.space = border.space
  }

  return normalized
}

function normalizeCellAttrsForExport(attrs: Record<string, unknown>): Record<string, unknown> {
  const next = { ...attrs }

  if (typeof next.backgroundColor === "string") {
    next.backgroundColor = next.backgroundColor.trim() || null
  }

  if (Array.isArray(next.colwidth)) {
    const colwidth = next.colwidth
      .map((value) => (typeof value === "number" && Number.isFinite(value) ? value : null))
      .filter((value): value is number => value != null && value > 0)
    if (colwidth.length) next.colwidth = colwidth
    else delete next.colwidth
  }

  for (const side of ["borderTop", "borderRight", "borderBottom", "borderLeft"] as const) {
    const normalized = normalizeTableBorderForExport(next[side])
    if (normalized) next[side] = normalized
    else delete next[side]
  }

  return next
}

function normalizeTableNodeForExport(node: TipTapJSON): TipTapJSON {
  if (!isRecord(node) || node.type !== "table") return node

  const rows = (Array.isArray(node.content) ? node.content : []) as TipTapJSON[]
  const firstRow = rows.find((row) => isRecord(row) && row.type === "tableRow")
  const firstRowCells = (Array.isArray(firstRow?.content) ? firstRow.content : []) as TipTapJSON[]
  const colwidths = firstRowCells
    .map((cell) => {
      if (!isRecord(cell) || !isRecord(cell.attrs)) return null
      const raw = cell.attrs.colwidth
      if (Array.isArray(raw) && typeof raw[0] === "number") return raw[0]
      if (typeof raw === "number") return raw
      return null
    })
    .filter((value): value is number => value != null && value > 0)

  const tableAttrs = isRecord(node.attrs) ? { ...node.attrs } : {}
  if (tableAttrs.layout === "fixed" && !colwidths.length) {
    delete tableAttrs.layout
  }

  const content = rows.map((row) => {
    if (!isRecord(row) || row.type !== "tableRow") return row

    const rowAttrs = isRecord(row.attrs) ? { ...row.attrs } : {}
    if (typeof rowAttrs.rowHeight === "string" && !rowAttrs.rowHeight.trim()) {
      delete rowAttrs.rowHeight
    }
    if (
      rowAttrs.rowHeightRule !== "exact" &&
      rowAttrs.rowHeightRule !== "atLeast"
    ) {
      delete rowAttrs.rowHeightRule
    }

    const cells = Array.isArray(row.content) ? row.content : []
    const normalizedCells = cells.map((cell, cellIndex) => {
      if (
        !isRecord(cell) ||
        (cell.type !== "tableCell" && cell.type !== "tableHeader")
      ) {
        return cell
      }

      const attrs = normalizeCellAttrsForExport(
        isRecord(cell.attrs) ? { ...cell.attrs } : {}
      )

      if (!attrs.colwidth && colwidths[cellIndex]) {
        attrs.colwidth = [colwidths[cellIndex]]
      }

      const cellContent = Array.isArray(cell.content)
        ? cell.content.map((child) => prepareTablesForDocxExport(child))
        : [{ type: "paragraph" }]

      return {
        ...cell,
        attrs: Object.keys(attrs).length ? attrs : undefined,
        content: cellContent,
      }
    })

    return {
      ...row,
      attrs: Object.keys(rowAttrs).length ? rowAttrs : undefined,
      content: normalizedCells,
    }
  })

  return {
    ...node,
    attrs: Object.keys(tableAttrs).length ? tableAttrs : undefined,
    content,
  }
}

/** Walk TipTap JSON and normalize table attrs before DOCX export. */
export function prepareTablesForDocxExport(content: TipTapJSON): TipTapJSON {
  if (!isRecord(content)) return content

  if (content.type === "table") {
    return normalizeTableNodeForExport(content)
  }

  if (Array.isArray(content.content)) {
    return {
      ...content,
      content: content.content.map((child) => prepareTablesForDocxExport(child)),
    }
  }

  return content
}
