import type { PptxElement, PptxFill } from "./pptxTypes"
import { getBorderInfo, getCacheKey, getNumber } from "./pptxUtils"
import { getMediaSrc } from "./pptxMedia"

type PatternShape =
  | { kind: "circle"; cx: number; cy: number; r: number; fill: string }
  | { kind: "polygon"; points: string; fill: string }
  | { kind: "rect"; x: number; y: number; width: number; height: number; fill: string; transform?: string }

export type ShapePattern = {
  id: string
  width: number
  height: number
  background: string
  shapes: PatternShape[]
}

export type GradientStop = {
  offset?: string
  color: string
  opacity?: number
}

export type ShapeGradient = {
  id: string
  kind: "linear" | "radial"
  x1?: string
  y1?: string
  x2?: string
  y2?: string
  stops: GradientStop[]
}

export type ShapeImagePaint = {
  id: string
  href: string
}

function toDomId(raw: string) {
  return raw.replace(/[^a-zA-Z0-9_-]/g, "_")
}

export function getShapePattern(el: PptxElement, slideIndex: number, cacheId: string): ShapePattern | null {
  const fill = typeof el.fill === "object" ? (el.fill as PptxFill) : null
  if (!fill || fill.type !== "pattern" || !fill.value) return null

  const type = String(fill.value?.type || "")
  const foreground = String(fill.value?.foregroundColor || "#000")
  const background = String(fill.value?.backgroundColor || "#fff")
  const id = `pptx-pattern-${slideIndex}-${toDomId(cacheId)}`

  if (type === "pct5") {
    return {
      id,
      width: 10,
      height: 10,
      background,
      shapes: [{ kind: "circle", cx: 5, cy: 5, r: 1.2, fill: foreground }],
    }
  }

  if (type === "solidDmnd") {
    return {
      id,
      width: 12,
      height: 12,
      background,
      shapes: [{ kind: "polygon", points: "6,0 12,6 6,12 0,6", fill: foreground }],
    }
  }

  return {
    id,
    width: 10,
    height: 10,
    background,
    shapes: [{ kind: "circle", cx: 5, cy: 5, r: 1, fill: foreground }],
  }
}

export function getShapeImagePaint(el: PptxElement, slideIndex: number, cacheId: string): ShapeImagePaint | null {
  const fill = typeof el.fill === "object" ? (el.fill as PptxFill) : null
  if (!fill) return null
  const v: any = (fill as any)?.value
  const looksLikeImageFill =
    fill.type === "image" ||
    (!!v && (typeof v.picBase64 === "string" || typeof v.src === "string")) ||
    typeof (fill as any).picBase64 === "string" ||
    typeof (fill as any).src === "string"

  if (!looksLikeImageFill) return null
  const href = getMediaSrc(el)
  if (!href) return null
  return {
    id: `pptx-shape-img-${slideIndex}-${toDomId(cacheId)}`,
    href,
  }
}

const shapeCache = {
  pattern: new Map<string, ShapePattern | null>(),
  image: new Map<string, ShapeImagePaint | null>(),
  gradient: new Map<string, ShapeGradient | null>(),
}

function getShapePatternCached(el: PptxElement, slideIndex: number, cacheId: string) {
  const key = `p-${getCacheKey(slideIndex, cacheId)}`
  if (shapeCache.pattern.has(key)) return shapeCache.pattern.get(key) as ShapePattern | null
  const value = getShapePattern(el, slideIndex, cacheId)
  shapeCache.pattern.set(key, value)
  return value
}

function getShapeImagePaintCached(el: PptxElement, slideIndex: number, cacheId: string) {
  const key = `i-${getCacheKey(slideIndex, cacheId)}`
  if (shapeCache.image.has(key)) return shapeCache.image.get(key) as ShapeImagePaint | null
  const value = getShapeImagePaint(el, slideIndex, cacheId)
  shapeCache.image.set(key, value)
  return value
}

function normalizeOffset(pos: unknown) {
  const s = String(pos ?? "").trim()
  if (!s) return ""
  if (s.endsWith("%")) return s
  const n = Number(s)
  if (Number.isFinite(n)) return `${n}%`
  return s
}

export function getShapeGradient(el: PptxElement, slideIndex: number, cacheId: string): ShapeGradient | null {
  const key = `g-${getCacheKey(slideIndex, cacheId)}`
  if (shapeCache.gradient.has(key)) return shapeCache.gradient.get(key) as ShapeGradient | null

  const fill = typeof el.fill === "object" ? (el.fill as PptxFill) : null
  if (!fill || fill.type !== "gradient" || !fill.value) {
    shapeCache.gradient.set(key, null)
    return null
  }

  const colors = Array.isArray(fill.value?.colors) ? fill.value.colors : []
  const rot = getNumber(fill.value?.rot)
  const path = String(fill.value?.path || "rect")
  const stops: GradientStop[] = colors
    .map((c: any) => {
      const offset = normalizeOffset(c?.pos)
      const color = String(c?.color ?? "").trim()
      const opacityRaw = c?.alpha ?? c?.opacity
      const opacity = opacityRaw == null ? undefined : Math.max(0, Math.min(1, getNumber(opacityRaw)))
      if (!color) return null
      return {
        offset: offset || undefined,
        color,
        opacity,
      }
    })
    .filter(Boolean) as any

  const id = `pptx-grad-${slideIndex}-${toDomId(cacheId)}`
  if (!stops.length) {
    shapeCache.gradient.set(key, null)
    return null
  }

  if (path !== "rect") {
    const result: ShapeGradient = {
      id,
      kind: "radial",
      stops: stops.map((s) => ({ ...s, offset: s.offset || "0%" })),
    }
    shapeCache.gradient.set(key, result)
    return result
  }

  const angle = ((90 - rot + 360) % 360) * (Math.PI / 180)
  const dx = Math.cos(angle)
  const dy = Math.sin(angle)
  const x1 = 0.5 - dx / 2
  const y1 = 0.5 + dy / 2
  const x2 = 0.5 + dx / 2
  const y2 = 0.5 - dy / 2

  const result: ShapeGradient = {
    id,
    kind: "linear",
    x1: `${Math.max(0, Math.min(1, x1)) * 100}%`,
    y1: `${Math.max(0, Math.min(1, y1)) * 100}%`,
    x2: `${Math.max(0, Math.min(1, x2)) * 100}%`,
    y2: `${Math.max(0, Math.min(1, y2)) * 100}%`,
    stops: stops.map((s) => ({ ...s, offset: s.offset || "0%" })),
  }
  shapeCache.gradient.set(key, result)
  return result
}

export function hasShapeDefs(el: PptxElement, slideIndex: number, cacheId: string) {
  return !!(getShapeGradient(el, slideIndex, cacheId) || getShapePatternCached(el, slideIndex, cacheId) || getShapeImagePaintCached(el, slideIndex, cacheId))
}

export function getShapeFill(el: PptxElement, slideIndex: number, cacheId: string) {
  const fill = typeof el.fill === "object" ? (el.fill as PptxFill) : null
  const isPic = String(el.type || "").toLowerCase().includes("pic")

  if ((!fill || !fill.type) && isPic) {
    const paint = getShapeImagePaintCached(el, slideIndex, cacheId)
    return paint ? `url(#${paint.id})` : "transparent"
  }
  if (!fill || !fill.type) return "transparent"
  if (fill.type === "color") return String(fill.value || "transparent")
  if (fill.type === "gradient") {
    const grad = getShapeGradient(el, slideIndex, cacheId)
    return grad ? `url(#${grad.id})` : "transparent"
  }
  if (fill.type === "pattern") {
    const pattern = getShapePatternCached(el, slideIndex, cacheId)
    return pattern ? `url(#${pattern.id})` : String(fill.value?.foregroundColor || "transparent")
  }
  if (fill.type === "image" || isPic || (fill.type == null && !!getShapeImagePaintCached(el, slideIndex, cacheId))) {
    const paint = getShapeImagePaintCached(el, slideIndex, cacheId)
    return paint ? `url(#${paint.id})` : "transparent"
  }
  return "transparent"
}

export function getShapeStroke(el: PptxElement) {
  const border = getBorderInfo(el)
  return border.color || "transparent"
}

export function getShapeStrokeWidth(el: PptxElement) {
  const border = getBorderInfo(el)
  return Math.max(0, border.width)
}

export function getShapeDasharray(el: PptxElement) {
  const border = getBorderInfo(el)
  return border.dasharray
}

export function getShapePath(el: PptxElement) {
  const raw = typeof (el as any).path === "string" ? String((el as any).path).trim() : ""
  if (raw) return raw

  const w = Math.max(0, getNumber(el.width))
  const h = Math.max(0, getNumber(el.height))

  const shapeType = String((el as any).shapType || (el as any).shapeType || (el as any).geom || "").toLowerCase()
  const isFlipH = !!(el as any).isFlipH
  const isFlipV = !!(el as any).isFlipV

  // 处理直线和连接符
  if (shapeType === "line" || shapeType === "connector" || shapeType === "straightconnector1") {
    // PPT 中的直线可能是从 (0,0) 到 (w,h)，也可能是从 (0,h) 到 (w,0)
    // 这里根据 flip 状态简单模拟，或者默认为对角线
    if (isFlipV && isFlipH) return `M ${w} ${h} L 0 0`
    if (isFlipV) return `M 0 ${h} L ${w} 0`
    if (isFlipH) return `M ${w} 0 L 0 ${h}`
    return `M 0 0 L ${w} ${h}`
  }

  // 如果宽度或高度为0，且不是直线，则尝试画一条极短的线或点以保持可见性
  if (w <= 0 || h <= 0) {
    if (w > 0) return `M 0 0 L ${w} 0`
    if (h > 0) return `M 0 0 L 0 ${h}`
    return ""
  }

  if (shapeType === "ellipse" || shapeType === "circle") {
    const cx = w / 2
    const cy = h / 2
    const rx = w / 2
    const ry = h / 2
    return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy} Z`
  }

  if (shapeType === "triangle" || shapeType === "tri") {
    return `M ${w / 2} 0 L ${w} ${h} L 0 ${h} Z`
  }

  if (shapeType === "diamond" || shapeType === "rhombus") {
    return `M ${w / 2} 0 L ${w} ${h / 2} L ${w / 2} ${h} L 0 ${h / 2} Z`
  }

  const r = Math.max(0, Math.min(Math.min(w, h) / 2, getNumber((el as any).radius || (el as any).cornerRadius || (el as any).rx)))
  if (r) {
    const rr = Math.min(r, w / 2, h / 2)
    return `M ${rr} 0 H ${w - rr} A ${rr} ${rr} 0 0 1 ${w} ${rr} V ${h - rr} A ${rr} ${rr} 0 0 1 ${w - rr} ${h} H ${rr} A ${rr} ${rr} 0 0 1 0 ${h - rr} V ${rr} A ${rr} ${rr} 0 0 1 ${rr} 0 Z`
  }

  return `M 0 0 H ${w} V ${h} H 0 Z`
}
