import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'

// ─── Types ────────────────────────────────────────────────────────────────────

export type ToastType = 'success' | 'error' | 'warning' | 'info'

export interface ToastItem {
  id: string
  type: ToastType
  title: string
  description?: string
  duration?: number
}

interface ToastContextValue {
  toast: (item: Omit<ToastItem, 'id'>) => void
  dismiss: (id: string) => void
}

// ─── Config ───────────────────────────────────────────────────────────────────

const toastConfig: Record<
  ToastType,
  {
    accent: string
    iconBg: string
    iconRing: string
    iconColor: string
    icon: string
    autoDismiss: boolean
  }
> = {
  success: {
    accent: 'bg-green-500',
    iconBg: 'bg-green-50',
    iconRing: 'ring-green-100',
    iconColor: 'text-green-500',
    icon: 'check',
    autoDismiss: true,
  },
  error: {
    accent: 'bg-red-500',
    iconBg: 'bg-red-50',
    iconRing: 'ring-red-100',
    iconColor: 'text-red-500',
    icon: 'error',
    autoDismiss: false,
  },
  warning: {
    accent: 'bg-amber-500',
    iconBg: 'bg-amber-50',
    iconRing: 'ring-amber-100',
    iconColor: 'text-amber-500',
    icon: 'warning',
    autoDismiss: true,
  },
  info: {
    accent: 'bg-blue-500',
    iconBg: 'bg-blue-50',
    iconRing: 'ring-blue-100',
    iconColor: 'text-blue-500',
    icon: 'info',
    autoDismiss: true,
  },
}

const DEFAULT_TOAST_DURATION = 5000

export const getToastDismissDuration = (item: ToastItem): number | null => {
  const cfg = toastConfig[item.type]
  if (item.duration !== undefined) {
    return item.duration > 0 ? item.duration : null
  }
  return cfg.autoDismiss ? DEFAULT_TOAST_DURATION : null
}

// ─── Context ──────────────────────────────────────────────────────────────────

const ToastContext = createContext<ToastContextValue | null>(null)

export function useToast(): ToastContextValue {
  const ctx = useContext(ToastContext)
  if (!ctx) throw new Error('useToast must be used inside <ToastProvider>')
  return ctx
}

// ─── Individual Toast ─────────────────────────────────────────────────────────

const ToastItem: React.FC<{ item: ToastItem; onDismiss: (id: string) => void }> = ({
  item,
  onDismiss,
}) => {
  const cfg = toastConfig[item.type]
  const timerRef = useRef<ReturnType<typeof setTimeout>>()
  const duration = getToastDismissDuration(item)

  useEffect(() => {
    if (duration !== null) {
      timerRef.current = setTimeout(() => onDismiss(item.id), duration)
    }
    return () => clearTimeout(timerRef.current)
  }, [item.id, duration, onDismiss])

  return (
    <div
      role="status"
      aria-live="polite"
      className="cp-toast-enter relative flex w-full max-w-sm overflow-hidden rounded-[10px] border border-slate-200/80 bg-white px-3.5 py-3.5 pr-2.5 shadow-soft-lg"
    >
      <span className={`absolute left-0 top-0 h-full w-0.5 ${cfg.accent}`} aria-hidden="true" />
      <div
        className={`ml-1 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg ring-1 ring-inset ${cfg.iconBg} ${cfg.iconRing}`}
      >
        <span className={`material-symbols-outlined text-[16px] leading-none ${cfg.iconColor}`}>
          {cfg.icon}
        </span>
      </div>
      <div className="min-w-0 flex-1 px-3">
        <p className="text-[12px] font-extrabold leading-5 text-slate-900">{item.title}</p>
        {item.description && (
          <p className="mt-0.5 text-[11px] leading-snug text-slate-500">{item.description}</p>
        )}
      </div>
      <button
        type="button"
        onClick={() => onDismiss(item.id)}
        className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg text-slate-300 transition-colors hover:bg-slate-100 hover:text-slate-600 focus:outline-2 focus:outline-teal-400 focus:outline-offset-2"
        aria-label="닫기"
      >
        <span className="material-symbols-outlined text-[16px] leading-none">close</span>
      </button>
      {duration !== null && (
        <span
          className={`cp-toast-progress absolute bottom-0 left-0 h-0.5 w-full ${cfg.accent}`}
          style={{ animationDuration: `${duration}ms` }}
          aria-hidden="true"
        />
      )}
    </div>
  )
}

// ─── Provider ─────────────────────────────────────────────────────────────────

const TOAST_STYLE_ID = 'cp-toast-styles'
const TOAST_KEYFRAMES = `
@keyframes cpSlideInFromRight {
  from { transform: translateX(calc(100% + 16px)); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}
@keyframes cpToastProgress {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}
.cp-toast-enter { animation: cpSlideInFromRight 0.3s ease-out both; }
.cp-toast-progress {
  animation-name: cpToastProgress;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
  transform-origin: left;
}
`

export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [toasts, setToasts] = useState<ToastItem[]>([])

  useEffect(() => {
    if (typeof document === 'undefined' || document.getElementById(TOAST_STYLE_ID)) return
    const style = document.createElement('style')
    style.id = TOAST_STYLE_ID
    style.textContent = TOAST_KEYFRAMES
    document.head.appendChild(style)
  }, [])

  const dismiss = useCallback((id: string) => {
    setToasts((prev) => prev.filter((t) => t.id !== id))
  }, [])

  const toast = useCallback((item: Omit<ToastItem, 'id'>) => {
    const id = `${Date.now()}-${Math.random()}`
    setToasts((prev) => {
      const next = [...prev, { ...item, id }]
      return next.slice(-3)
    })
  }, [])

  return (
    <ToastContext.Provider value={{ toast, dismiss }}>
      {children}
      {typeof document !== 'undefined' &&
        createPortal(
          <div
            className="fixed right-4 top-4 z-50 flex w-[calc(100vw-2rem)] max-w-sm flex-col gap-2"
            aria-live="polite"
            role="region"
            aria-label="알림"
          >
            {toasts.map((item) => (
              <ToastItem key={item.id} item={item} onDismiss={dismiss} />
            ))}
          </div>,
          document.body
        )}
    </ToastContext.Provider>
  )
}
