'use client'

import classNames from 'classnames'
import { forwardRef, HTMLAttributes, ReactNode, useEffect, useState } from 'react'

import { PktIcon } from '../icon/Icon'

declare global {
  interface Window {
    pktAnimationPath?: string
  }
}

if (typeof window !== 'undefined') {
  window.pktAnimationPath =
    window.pktAnimationPath || 'https://punkt-cdn.oslo.kommune.no/latest/animations/'
}

export type TPktLoaderVariant = 'blue' | 'rainbow' | 'shapes'
export type TPktLoaderSize = 'small' | 'medium' | 'large'

export interface IPktLoader extends HTMLAttributes<HTMLDivElement> {
  /**
   * Tid i millisekunder før loader vises. Nyttig når lastetiden kan være
   * så kort at loader ikke trengs.
   */
  delay?: number
  /**
   * Vises loader inline eller som blokk.
   */
  inline?: boolean
  /**
   * Styrer om loader eller barnenoder vises. Når `false` vises barnenoder.
   */
  isLoading?: boolean
  /**
   * Meldingstekst som vises sammen med loader.
   */
  message?: string | null
  /**
   * Størrelse på loader. Standard er "medium".
   */
  size?: TPktLoaderSize
  /**
   * Loader-variant. Standard er "shapes" (Oslo-bølger). Andre er "blue" og "rainbow" (spinner-varianter).
   */
  variant?: TPktLoaderVariant
  /**
   * Overstyrer stien til loader-animasjoner.
   */
  loadingAnimationPath?: string
  children?: ReactNode
}

const variantIcon = (variant: TPktLoaderVariant): string => {
  switch (variant) {
    case 'blue':
      return 'spinner-blue'
    case 'rainbow':
      return 'spinner'
    default:
      return 'loader'
  }
}

export const PktLoader = forwardRef<HTMLDivElement, IPktLoader>(function PktLoader(
  {
    delay = 0,
    inline = false,
    isLoading = true,
    message = null,
    size = 'medium',
    variant = 'shapes',
    loadingAnimationPath = typeof window !== 'undefined' ? window.pktAnimationPath : undefined,
    className,
    children,
    ...rest
  },
  ref,
) {
  const [shouldDisplayLoader, setShouldDisplayLoader] = useState(delay === 0)

  useEffect(() => {
    if (delay > 0) {
      setShouldDisplayLoader(false)
      const handle = setTimeout(() => setShouldDisplayLoader(true), delay)
      return () => clearTimeout(handle)
    }
    setShouldDisplayLoader(true)
  }, [delay])

  const classes = classNames(
    'pkt-loader',
    inline ? 'pkt-loader--inline' : 'pkt-loader--box',
    `pkt-loader--${size}`,
    className,
  )

  return (
    <div
      {...rest}
      ref={ref}
      role="status"
      aria-live="polite"
      aria-busy={isLoading ? 'true' : 'false'}
      className={classes}
    >
      {isLoading && shouldDisplayLoader && (
        <div className="pkt-loader__spinner">
          <PktIcon
            name={variantIcon(variant)}
            path={loadingAnimationPath}
            className={`pkt-loader__svg pkt-loader__${variant}`}
          />
          {message && <p>{message}</p>}
        </div>
      )}
      <div className={classNames('pkt-contents', isLoading && 'pkt-hide')}>{children}</div>
    </div>
  )
})

PktLoader.displayName = 'PktLoader'
