import { useEffect, useRef } from 'react'
import type { HTMLAttributes, ReactNode } from 'react'
import { motion } from 'framer-motion'
import { SparklingLine } from '../basic/icons-inline'

export interface ImageGeneratingProps extends HTMLAttributes<HTMLDivElement> {
  width?: string
  height?: string
  speed?: number
  caption?: string
  captionClassName?: string
  showOverlay?: boolean
  overlayText?: string
  sparklingIcon?: ReactNode
}

function cn(...inputs: (string | undefined | false)[]): string {
  return inputs.filter(Boolean).join(' ')
}

const defaultSparkling = <SparklingLine className="h-5 w-5 text-text-on-primary" />

export function ImageGenerating({
  width = 'var(--spacing-80)',
  height = 'var(--spacing-60)',
  speed = 1.0,
  caption = 'Spark is drawing...',
  captionClassName,
  className,
  style: styleProp,
  showOverlay = false,
  overlayText,
  sparklingIcon = defaultSparkling,
  ...props
}: ImageGeneratingProps) {
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (typeof CSS !== 'undefined' && CSS.registerProperty) {
      try {
        CSS.registerProperty({ name: '--a', syntax: '<angle>', inherits: true, initialValue: '0deg' })
        CSS.registerProperty({ name: '--l', syntax: '<number>', inherits: true, initialValue: '0' })
        CSS.registerProperty({ name: '--x', syntax: '<length>', inherits: false, initialValue: '0' })
        CSS.registerProperty({ name: '--y', syntax: '<length>', inherits: false, initialValue: '0' })
        CSS.registerProperty({ name: '--o', syntax: '<number>', inherits: false, initialValue: '0' })
        CSS.registerProperty({ name: '--value', syntax: '<angle>', inherits: true, initialValue: '0deg' })
        CSS.registerProperty({ name: '--width-ratio', syntax: '<number>', inherits: true, initialValue: '0' })
        CSS.registerProperty({ name: '--scale', syntax: '<number>', inherits: true, initialValue: '0' })
      } catch {
        // ignore
      }
    }
  }, [])

  useEffect(() => {
    const container = containerRef.current
    if (!container) return
    const updateSize = () => {
      const rect = container.getBoundingClientRect()
      if (rect.width > 0 && rect.height > 0) {
        const size = Math.max(rect.width, rect.height)
        container.style.setProperty('--actual-size', `${size}px`)
      }
    }
    const isPercent = (typeof width === 'string' && width.includes('%')) || (typeof height === 'string' && height.includes('%'))
    let resizeObserver: ResizeObserver | null = null
    const setup = () => {
      updateSize()
      resizeObserver = new ResizeObserver(updateSize)
      resizeObserver.observe(container)
    }
    if (isPercent) {
      const id = requestAnimationFrame(() => setup())
      return () => {
        cancelAnimationFrame(id)
        resizeObserver?.disconnect()
      }
    }
    setup()
    return () => resizeObserver?.disconnect()
  }, [width, height])

  return (
    <>
      <style>{`
        @keyframes ai {
          from { --a: 360deg; --l: 0.35; --o: 1; }
          30% { --l: 1.5; }
          70% { --o: 0.4; --l: 0.05; }
          98% { --o: 0.7; }
          to { --a: 0deg; --l: 0.35; --o: 1; }
        }
        @keyframes ring {
          from { --value: var(--start); --scale: 1; }
          50% { --scale: 1.2; --width-ratio: 1.5; }
          70% { --scale: 1; --value: calc(var(--start) + 180deg); --width-ratio: 1; }
          80% { --scale: 1.2; --width-ratio: 1.5; }
          to { --value: calc(var(--start) + 360deg); --scale: 1; --width-ratio: 1; }
        }
        .image-generating-container {
          --s: var(--actual-size, max(var(--container-width), var(--container-height)));
          --p: calc(var(--s) / 4);
          --radius: calc(var(--s) * 0.25);
          --count: 4;
          --width: calc(var(--s) * 0.025);
          --duration: calc(8s / var(--image-generating-speed, 1));
          --ai-duration: calc(5.5s / var(--image-generating-speed, 1));
          width: var(--container-width);
          height: var(--container-height);
          --bg-color: color-mix(in srgb, var(--color-primary), transparent 92%);
          background: radial-gradient(60% 75% at center, var(--bg-color) 50%, transparent 50%),
            radial-gradient(75% 60% at center, var(--bg-color) 50%, transparent 50%);
          overflow: hidden;
          position: relative;
          border-radius: var(--radius-xl);
        }
        .image-generating-container .fluid-inner {
          overflow: hidden;
          background: var(--color-bg-base);
          width: 100%;
          height: 100%;
          position: relative;
          display: grid;
          place-items: center;
          border-radius: var(--radius-xl);
        }
        .image-generating-container .c {
          opacity: 0.9;
          position: absolute;
          width: calc(var(--s) * 0.4);
          aspect-ratio: 1;
          border-radius: 50%;
          --offset-per-item: calc(360deg / var(--count));
          --current-angle-offset: calc(var(--offset-per-item) * var(--i) + var(--a));
          translate: calc(cos(var(--current-angle-offset)) * var(--radius) + var(--x, 0))
            calc(sin(var(--current-angle-offset)) * var(--radius) * -1);
          scale: calc(0.6 + var(--l));
          animation: ai var(--ai-duration) cubic-bezier(0.45, -0.35, 0.16, 1.5) infinite;
          transition: opacity 0.3s linear;
          opacity: var(--o, 1);
        }
        .image-generating-container .c1 {
          background: radial-gradient(50% 50% at center, var(--color-primary), color-mix(in srgb, var(--color-primary), transparent 30%));
          --x: calc(var(--s) * 0.04);
          width: calc(var(--s) * 0.6);
          animation-timing-function: cubic-bezier(0.12, 0.32, 0.68, 0.24);
        }
        .image-generating-container .c2 {
          background: radial-gradient(50% 50% at center, var(--color-primary-active), color-mix(in srgb, var(--color-primary-active), var(--color-bg-base) 45%));
          width: calc(var(--s) * 0.55);
        }
        .image-generating-container .c3 {
          background: radial-gradient(50% 50% at center, var(--color-primary-hover), transparent);
          width: calc(var(--s) * 0.2);
          opacity: 0.6;
          --x: calc(var(--s) * -0.04);
        }
        .image-generating-container .c4 {
          background: var(--color-primary-border-hover);
          animation-timing-function: cubic-bezier(0.39, -0.03, 0.75, 0.47);
        }
        .image-generating-container .glass {
          overflow: hidden;
          position: absolute;
          inset: 0;
          backdrop-filter: blur(calc(var(--s) * 0.12));
          box-shadow: 0 0 calc(var(--s) * 0.2) color-mix(in srgb, var(--color-text-base), transparent 70%);
          border-radius: var(--radius-xl);
          pointer-events: none;
        }
        .image-generating-container .glass::after {
          content: "";
          position: absolute;
          inset: 0;
          --c: color-mix(in srgb, var(--color-text-base), transparent 97%);
          --w: 0.0625rem;
          --g: 0.1875rem;
          background: repeating-linear-gradient(
            var(--c), var(--c), var(--w), transparent var(--w), transparent calc(var(--w) + var(--g))
          );
          border-radius: var(--radius-xl);
        }
        .image-generating-container .rings {
          aspect-ratio: 1;
          border-radius: 50%;
          position: absolute;
          inset: 0;
          perspective: calc(var(--s) * 2.75);
          opacity: 0.9;
        }
        .image-generating-container .rings::before,
        .image-generating-container .rings::after {
          content: "";
          position: absolute;
          inset: 0;
          border-radius: 50%;
          --width-ratio: 1;
          border: calc(var(--width) * var(--width-ratio)) solid transparent;
          mask: linear-gradient(var(--color-image-generating-mask, var(--color-bg-base)) 0 0) padding-box, linear-gradient(var(--color-image-generating-mask, var(--color-bg-base)) 0 0);
          background: linear-gradient(
            var(--color-bg-base),
            var(--color-primary),
            var(--color-primary-active),
            var(--color-primary-hover)
          ) border-box;
          mask-composite: exclude;
          animation: ring var(--duration) ease-in-out infinite;
          --start: 180deg;
          --value: var(--start);
          --scale: 1;
          transform: rotateY(var(--value)) rotateX(var(--value)) rotateZ(var(--value)) scale(var(--scale));
        }
        .image-generating-container .rings::before { --start: 180deg; }
        .image-generating-container .rings::after { --start: 90deg; }
        .image-generating-container .content-overlay {
          position: absolute;
          inset: 0;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          gap: var(--spacing-3);
          z-index: 2;
          pointer-events: none;
        }
        .image-generating-container .content-overlay .caption {
          font-size: var(--font-size-xs);
          font-weight: 500;
          color: var(--color-text-on-primary);
        }
        .image-generating-container .remaining-overlay {
          background: var(--color-bg-mask);
          border-radius: var(--radius-xl);
        }
        .image-generating-container .remaining-text {
          font-size: var(--font-size-3xl);
          font-weight: 600;
          color: var(--color-text-on-primary);
        }
      `}</style>
      <div
        ref={containerRef}
        className={cn('image-generating-container', className)}
        style={{
          ['--container-width' as string]: width,
          ['--container-height' as string]: height,
          ['--image-generating-speed' as string]: String(speed),
          ...(styleProp && typeof styleProp === 'object' ? styleProp : {}),
        }}
        {...props}
      >
        <div className="fluid-inner">
          <div className="c c4" style={{ ['--i' as string]: 0 }} />
          <div className="c c1" style={{ ['--i' as string]: 1 }} />
          <div className="c c2" style={{ ['--i' as string]: 2 }} />
          <div className="c c3" style={{ ['--i' as string]: 3 }} />
          <div className="rings" />
        </div>
        <div className="glass" />
        {showOverlay ? (
          <div className="content-overlay remaining-overlay">
            <span className="remaining-text">{overlayText}</span>
          </div>
        ) : (
          <div className="content-overlay">
            <motion.span
              className="inline-flex items-center justify-center"
              animate={{ scale: [1, 1.08, 1], opacity: [0.9, 1, 0.9] }}
              transition={{ duration: 1.2, repeat: Infinity, ease: [0.16, 1, 0.3, 1] as const }}
            >
              {sparklingIcon}
            </motion.span>
            <span className={cn('caption', captionClassName)}>{caption}</span>
          </div>
        )}
      </div>
    </>
  )
}

ImageGenerating.displayName = 'ImageGenerating'
export const ImageGenerationPlaceholder = ImageGenerating
export type ImageGenerationPlaceholderProps = ImageGeneratingProps
