export type DocParagraphStyleScope = "document" | "user"

export type DocParagraphStyleBlockType = "paragraph" | "heading"

export type DocParagraphStyleDefinition = {
  id: string
  name: string
  scope: DocParagraphStyleScope
  basedOn?: string
  blockType: DocParagraphStyleBlockType
  level?: number
  fontFamily?: string
  fontSizePx?: number
  bold?: boolean
  italic?: boolean
  underline?: boolean
  color?: string
  textAlign?: "left" | "center" | "right" | "justify"
  lineHeight?: number
  spaceBeforePt?: number
  spaceAfterPt?: number
}

export type DocParagraphStylesCatalog = {
  definitions: Record<string, DocParagraphStyleDefinition>
}

export const BUILTIN_PARAGRAPH_STYLE_IDS = [
  "normal",
  "title",
  "subtitle",
  "heading1",
  "heading2",
  "heading3",
  "heading4",
  "heading5",
  "heading6",
] as const

export type BuiltinParagraphStyleId = (typeof BUILTIN_PARAGRAPH_STYLE_IDS)[number]

const BUILTIN_LABELS: Record<BuiltinParagraphStyleId, string> = {
  normal: "Normal",
  title: "Titre",
  subtitle: "Sous-titre",
  heading1: "Titre 1",
  heading2: "Titre 2",
  heading3: "Titre 3",
  heading4: "Titre 4",
  heading5: "Titre 5",
  heading6: "Titre 6",
}

export function normalizeParagraphStyleId(styleId: string): string {
  if (styleId === "paragraph") return "normal"
  return styleId
}

export function defaultDocumentParagraphStyles(): DocParagraphStylesCatalog {
  const defs: Record<string, DocParagraphStyleDefinition> = {
    normal: {
      id: "normal",
      name: BUILTIN_LABELS.normal,
      scope: "document",
      blockType: "paragraph",
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 11,
      lineHeight: 1.15,
    },
    title: {
      id: "title",
      name: BUILTIN_LABELS.title,
      scope: "document",
      blockType: "paragraph",
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 26,
      lineHeight: 1.15,
    },
    subtitle: {
      id: "subtitle",
      name: BUILTIN_LABELS.subtitle,
      scope: "document",
      blockType: "paragraph",
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 15,
      color: "#666666",
      lineHeight: 1.15,
    },
    heading1: {
      id: "heading1",
      name: BUILTIN_LABELS.heading1,
      scope: "document",
      blockType: "heading",
      level: 1,
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 20,
      lineHeight: 1.15,
    },
    heading2: {
      id: "heading2",
      name: BUILTIN_LABELS.heading2,
      scope: "document",
      blockType: "heading",
      level: 2,
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 16,
      lineHeight: 1.15,
    },
    heading3: {
      id: "heading3",
      name: BUILTIN_LABELS.heading3,
      scope: "document",
      blockType: "heading",
      level: 3,
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 14,
      lineHeight: 1.15,
    },
    heading4: {
      id: "heading4",
      name: BUILTIN_LABELS.heading4,
      scope: "document",
      blockType: "heading",
      level: 4,
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 12,
      bold: true,
      lineHeight: 1.15,
    },
    heading5: {
      id: "heading5",
      name: BUILTIN_LABELS.heading5,
      scope: "document",
      blockType: "heading",
      level: 5,
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 11,
      bold: true,
      lineHeight: 1.15,
    },
    heading6: {
      id: "heading6",
      name: BUILTIN_LABELS.heading6,
      scope: "document",
      blockType: "heading",
      level: 6,
      fontFamily: "Arial, Helvetica, sans-serif",
      fontSizePx: 11,
      italic: true,
      lineHeight: 1.15,
    },
  }
  return { definitions: defs }
}

export function emptyUserParagraphStyles(): DocParagraphStylesCatalog {
  return { definitions: {} }
}

function styleRunKey(def: DocParagraphStyleDefinition): string {
  return JSON.stringify({
    fontFamily: def.fontFamily ?? "",
    fontSizePx: def.fontSizePx ?? null,
    bold: def.bold ?? false,
    italic: def.italic ?? false,
    underline: def.underline ?? false,
    color: def.color ?? "",
    textAlign: def.textAlign ?? "",
    lineHeight: def.lineHeight ?? null,
    blockType: def.blockType,
    level: def.level ?? null,
  })
}

export function paragraphStylesDiffer(
  a: DocParagraphStyleDefinition | undefined,
  b: DocParagraphStyleDefinition | undefined
): boolean {
  if (!a || !b) return Boolean(a || b)
  return styleRunKey(a) !== styleRunKey(b)
}

export function mergeParagraphStyleCatalogs(
  documentStyles: DocParagraphStylesCatalog | null | undefined,
  userStyles: DocParagraphStylesCatalog | null | undefined
): DocParagraphStylesCatalog {
  const base = defaultDocumentParagraphStyles()
  const docDefs = { ...base.definitions, ...(documentStyles?.definitions ?? {}) }
  const merged = { ...docDefs, ...(userStyles?.definitions ?? {}) }
  return { definitions: merged }
}

export type ParagraphStyleMenuEntry = {
  definition: DocParagraphStyleDefinition
  section: "document" | "user"
}

export function buildParagraphStyleMenuEntries(
  documentStyles: DocParagraphStylesCatalog,
  userStyles: DocParagraphStylesCatalog
): ParagraphStyleMenuEntry[] {
  const docBase = defaultDocumentParagraphStyles()
  const docDefs = { ...docBase.definitions, ...documentStyles.definitions }
  const entries: ParagraphStyleMenuEntry[] = []

  for (const id of BUILTIN_PARAGRAPH_STYLE_IDS) {
    const def = docDefs[id]
    if (def) entries.push({ definition: def, section: "document" })
  }

  for (const id of BUILTIN_PARAGRAPH_STYLE_IDS) {
    const userDef = userStyles.definitions[id]
    const docDef = docDefs[id]
    if (userDef && paragraphStylesDiffer(docDef, userDef)) {
      entries.push({ definition: { ...userDef, scope: "user" }, section: "user" })
    }
  }

  for (const def of Object.values(userStyles.definitions)) {
    if (def.scope !== "user") continue
    if ((BUILTIN_PARAGRAPH_STYLE_IDS as readonly string[]).includes(def.id)) continue
    entries.push({ definition: def, section: "user" })
  }

  return entries
}

export function resolveParagraphStyleDefinition(
  catalog: DocParagraphStylesCatalog,
  styleId: string
): DocParagraphStyleDefinition | null {
  const id = normalizeParagraphStyleId(styleId)
  return catalog.definitions[id] ?? defaultDocumentParagraphStyles().definitions[id] ?? null
}

export function inferParagraphStyleIdFromEditorState(input: {
  styleId?: string | null
  isHeading?: boolean
  headingLevel?: number
}): string {
  if (input.styleId) return normalizeParagraphStyleId(input.styleId)
  if (input.isHeading && input.headingLevel) return `heading${input.headingLevel}`
  return "normal"
}

export function createCustomParagraphStyle(input: {
  name: string
  basedOn?: string
  template?: DocParagraphStyleDefinition
}): DocParagraphStyleDefinition {
  const id = `custom-${typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID().slice(0, 8) : Math.random().toString(36).slice(2, 10)}`
  const base =
    input.template ??
    resolveParagraphStyleDefinition(defaultDocumentParagraphStyles(), input.basedOn ?? "normal")!
  return {
    ...base,
    id,
    name: input.name.trim() || "Style personnalisé",
    scope: "user",
    basedOn: input.basedOn ?? base.id,
  }
}

export function builtinParagraphStyleLabel(id: string): string {
  const normalized = normalizeParagraphStyleId(id) as BuiltinParagraphStyleId
  return BUILTIN_LABELS[normalized] ?? id
}
