interface Particle {
  x: number
  y: number
  vx: number
  vy: number
  size: number
  alpha: number
  life: number
  maxLife: number
  originX: number
}

interface SmokeState {
  element: HTMLElement
  canvas: HTMLCanvasElement
  ctx: CanvasRenderingContext2D
  particles: Particle[]
  isActive: boolean
  animationFrame: number | null
}

const createParticle = (
  x: number,
  y: number,
  elementWidth: number,
): Particle => {
  const spreadFactor = Math.max(1, elementWidth / 100)

  return {
    x,
    y,
    originX: x,
    vx: (Math.random() - 0.5) * spreadFactor * 2,
    vy: -Math.random() * 3 - 2,
    // Reduced initial size range
    size: Math.random() * 3 + 2,
    alpha: 1,
    life: 0,
    maxLife: Math.random() * 100 + 100,
  }
}

const updateParticle = (particle: Particle): Particle => {
  const distanceFromOrigin = Math.abs(particle.x - particle.originX)
  const returnForce =
    distanceFromOrigin > 100 ? (particle.originX - particle.x) * 0.001 : 0

  return {
    ...particle,
    x: particle.x + particle.vx + returnForce,
    y: particle.y + particle.vy,
    vx: particle.vx + (Math.random() - 0.5) * 0.1,
    // Reduced size growth rate
    size: particle.size + 0.1,
    life: particle.life + 1,
    alpha: Math.max(0, 1 - particle.life / particle.maxLife),
  }
}

const isParticleAlive = (particle: Particle): boolean =>
  particle.life < particle.maxLife

const setupCanvas = (canvas: HTMLCanvasElement): void => {
  canvas.style.position = "fixed"
  canvas.style.pointerEvents = "none"
  // Maximum possible z-index
  canvas.style.zIndex = "2147483647"
  document.body.appendChild(canvas)
}

const positionCanvas = (canvas: HTMLCanvasElement): void => {
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  canvas.style.left = "0"
  canvas.style.top = "0"
}

const addParticle = (state: SmokeState): Particle => {
  const rect = state.element.getBoundingClientRect()
  const randomOffset = (Math.random() - 0.5) * rect.width
  const x = rect.left + rect.width / 2 + randomOffset
  const y = rect.top + rect.height / 2

  return createParticle(x, y, rect.width)
}

const drawParticle = (
  ctx: CanvasRenderingContext2D,
  particle: Particle,
): void => {
  ctx.beginPath()
  ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2)
  // Increased particle count but reduced alpha for more smoke-like appearance
  ctx.fillStyle = `rgba(128, 128, 128, ${particle.alpha * 0.3})`
  ctx.fill()
}

const animate = (state: SmokeState): void => {
  if (!state.isActive) {
    return
  }

  state.ctx.clearRect(0, 0, state.canvas.width, state.canvas.height)

  const rect = state.element.getBoundingClientRect()
  // Increased particle generation rate to compensate for smaller particles
  const particleRate = Math.max(0.5, rect.width / 200)

  if (Math.random() < particleRate) {
    state.particles.push(addParticle(state))
  }

  state.particles = state.particles.map(updateParticle).filter((particle) => {
    if (isParticleAlive(particle)) {
      drawParticle(state.ctx, particle)

      return true
    }

    return false
  })

  state.animationFrame = requestAnimationFrame(() => animate(state))
}

const createSmokeEffect = (element: HTMLElement) => {
  const canvas = document.createElement("canvas")
  const ctx = canvas.getContext("2d")!

  const state: SmokeState = {
    element,
    canvas,
    ctx,
    particles: [],
    isActive: false,
    animationFrame: null,
  }

  setupCanvas(canvas)
  positionCanvas(canvas)

  window.addEventListener("resize", () => positionCanvas(canvas))

  const start = () => {
    if (state.isActive) {
      return
    }
    state.isActive = true
    animate(state)
  }

  const stop = () => {
    state.isActive = false
    if (state.animationFrame !== null) {
      cancelAnimationFrame(state.animationFrame)
    }
    state.particles = []
    state.ctx.clearRect(0, 0, state.canvas.width, state.canvas.height)
  }

  const destroy = () => {
    stop()
    state.canvas.remove()
  }

  return {
    start,
    stop,
    destroy,
  }
}

export default createSmokeEffect
