import { useEffect, useRef, useState, type CSSProperties } from "react"
import { createPortal } from "react-dom"
import { CheckCircle2, AlertCircle, Info, X } from "lucide-react"

/**
 * 全局 Toast 系统（右上角层叠堆叠）
 *
 * 使用：
 *   import { toast } from "@/utils/toast"
 *   toast.success("登录成功")
 *   toast.error("密码错误")
 *   toast.info("提示信息")
 *
 * <ToastHost /> 已挂载在 main.tsx，无需重复挂载。
 *
 * 视觉：
 *   - 最新一条在最前；旧条目沿垂直方向探出顶部、缩小、变淡
 *   - 入场：从右滑入；离开：向右滑出 + 高度坍缩，下方条目"塌下来"
 *   - 双层 wrapper：外层管堆叠，内层管生命周期，避免 transform 打架
 */

export type ToastKind = "success" | "error" | "info"

interface ToastItem {
  id: number
  kind: ToastKind
  message: string
}

const STYLE_ID = "qycw-toast-styles"
const TOAST_CSS = `
.qycw-toast-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
  width: 380px;
  max-width: calc(100vw - 40px);
  pointer-events: none;
}
.qycw-toast-stack {
  position: absolute;
  top: 0;
  right: 0;
  width: 100%;
  transform-origin: top right;
  transition:
    transform 460ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 360ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform, opacity;
}
.qycw-toast-life {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  background: #ffffff;
  border: 1px solid #eef2f7;
  border-radius: 14px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.10), 0 4px 10px rgba(15, 23, 42, 0.05);
  font-size: 14px;
  color: #334155;
  transform-origin: top right;
  transition:
    transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 280ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform, opacity;
}
/* 入场前的初始位 */
.qycw-toast-life[data-state="entering"] {
  transform: translateX(120%);
  opacity: 0;
}
/* 在场静止位 */
.qycw-toast-life[data-state="active"] {
  transform: translateX(0);
  opacity: 1;
}
/* 离开：向右滑出 + 缩小 + 淡出，曲线偏 ease-in */
.qycw-toast-life[data-state="leaving"] {
  transform: translateX(108%) scale(0.96);
  opacity: 0;
  transition:
    transform 360ms cubic-bezier(0.55, 0.06, 0.68, 0.19),
    opacity 240ms cubic-bezier(0.55, 0.06, 0.68, 0.19);
}
/* 堆叠容器在元素离开时：高度坍缩，让下方 toast 平滑塌下来 */
.qycw-toast-stack[data-leaving="true"] {
  /* 在 JS 中将 max-height 显式置 0；这里给一个回退过渡 */
  transition:
    transform 460ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 360ms cubic-bezier(0.22, 1, 0.36, 1),
    max-height 360ms cubic-bezier(0.4, 0, 0.2, 1),
    margin-top 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.qycw-toast-icon { flex-shrink: 0; margin-top: 1px; }
.qycw-toast-success .qycw-toast-icon { color: #22c55e; }
.qycw-toast-error   .qycw-toast-icon { color: #ef4444; }
.qycw-toast-info    .qycw-toast-icon { color: #0ea5e9; }
.qycw-toast-msg {
  flex: 1;
  line-height: 1.5;
  word-break: break-word;
  font-weight: 500;
  color: #1e293b;
}
.qycw-toast-close {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  color: #94a3b8;
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.qycw-toast-close:hover { background: #f1f5f9; color: #475569; }
@media (prefers-reduced-motion: reduce) {
  .qycw-toast-stack, .qycw-toast-life {
    transition-duration: 160ms !important;
    transition-timing-function: linear !important;
  }
}
`

let cssInjected = false
function ensureCss() {
  if (cssInjected) return
  if (typeof document === "undefined") return
  if (document.getElementById(STYLE_ID)) {
    cssInjected = true
    return
  }
  const style = document.createElement("style")
  style.id = STYLE_ID
  style.textContent = TOAST_CSS
  document.head.appendChild(style)
  cssInjected = true
}
ensureCss()

const TOAST_EVENT = "qycw:toast"
const DURATION = 3800
const LEAVE_MS = 380
const STACK_OFFSET = 10
const STACK_SCALE = 0.04
const STACK_OPACITY_DECAY = 0.18
const MAX_VISIBLE = 3

let nextId = 1

interface ToastDetail {
  kind: ToastKind
  message: string
}

export const toast = {
  success: (message: unknown) => emit({ kind: "success", message: normalizeToastMessage(message) }),
  error: (message: unknown) => emit({ kind: "error", message: normalizeToastMessage(message) }),
  info: (message: unknown) => emit({ kind: "info", message: normalizeToastMessage(message) }),
}

function emit(detail: ToastDetail) {
  if (typeof window === "undefined") return
  window.dispatchEvent(new CustomEvent<ToastDetail>(TOAST_EVENT, { detail }))
}

function normalizeToastMessage(message: unknown): string {
  if (typeof message === "string") return message
  if (message == null) return ""
  if (Array.isArray(message)) {
    return message
      .map((item) => {
        if (typeof item === "string") return item
        if (item && typeof item === "object" && "msg" in item) return String((item as { msg?: unknown }).msg ?? "")
        return JSON.stringify(item)
      })
      .filter(Boolean)
      .join("；")
  }
  if (typeof message === "object" && "msg" in message) {
    return String((message as { msg?: unknown }).msg ?? "")
  }
  return String(message)
}

function stackStyle(index: number): CSSProperties {
  if (index >= MAX_VISIBLE) {
    return {
      transform: `translateY(-${MAX_VISIBLE * STACK_OFFSET}px) scale(${1 - MAX_VISIBLE * STACK_SCALE})`,
      opacity: 0,
      pointerEvents: "none",
    }
  }
  return {
    transform: `translateY(-${index * STACK_OFFSET}px) scale(${1 - index * STACK_SCALE})`,
    opacity: 1 - index * STACK_OPACITY_DECAY,
  }
}

type LifeState = "entering" | "active" | "leaving"

export function ToastHost() {
  const [items, setItems] = useState<ToastItem[]>([])
  const [states, setStates] = useState<Record<number, LifeState>>({})
  const timersRef = useRef<Record<number, number>>({})

  const dismiss = (id: number) => {
    setStates((s) => (s[id] === "leaving" ? s : { ...s, [id]: "leaving" }))
    window.setTimeout(() => {
      setItems((prev) => prev.filter((t) => t.id !== id))
      setStates((s) => {
        const n = { ...s }
        delete n[id]
        return n
      })
      const auto = timersRef.current[id]
      if (auto) {
        window.clearTimeout(auto)
        delete timersRef.current[id]
      }
    }, LEAVE_MS)
  }

  useEffect(() => {
    const onToast = (e: Event) => {
      const detail = (e as CustomEvent<ToastDetail>).detail
      const id = nextId++
      // 入场初始 state = entering
      setItems((prev) => [{ id, kind: detail.kind, message: detail.message }, ...prev])
      setStates((s) => ({ ...s, [id]: "entering" }))
      // 双 rAF：保证浏览器先按 entering 布局，再切到 active 触发过渡
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          setStates((s) => (s[id] === "entering" ? { ...s, [id]: "active" } : s))
        })
      })
      timersRef.current[id] = window.setTimeout(() => dismiss(id), DURATION)
    }

    window.addEventListener(TOAST_EVENT, onToast)
    return () => {
      window.removeEventListener(TOAST_EVENT, onToast)
      Object.values(timersRef.current).forEach((t) => window.clearTimeout(t))
      timersRef.current = {}
    }
  }, [])

  if (typeof document === "undefined") return null

  return createPortal(
    <div className="qycw-toast-container" aria-live="polite" aria-atomic="true">
      {items.map((t, i) => {
        const Icon = t.kind === "success" ? CheckCircle2 : t.kind === "error" ? AlertCircle : Info
        const state = states[t.id] ?? "entering"
        return (
          <div
            key={t.id}
            className="qycw-toast-stack"
            data-leaving={state === "leaving" ? "true" : "false"}
            style={{
              ...stackStyle(i),
              zIndex: items.length - i,
            }}
          >
            <div
              className={`qycw-toast-life qycw-toast-${t.kind}`}
              data-state={state}
              role={t.kind === "error" ? "alert" : "status"}
            >
              <Icon className="qycw-toast-icon h-5 w-5" />
              <div className="qycw-toast-msg">{t.message}</div>
              <button
                type="button"
                className="qycw-toast-close"
                onClick={() => dismiss(t.id)}
                aria-label="关闭"
              >
                <X className="h-3.5 w-3.5" />
              </button>
            </div>
          </div>
        )
      })}
    </div>,
    document.body,
  )
}
