import * as React from 'react'
import { cva } from 'class-variance-authority'

import { cn } from './utils'

/* ------------------------------------------------------------------ */
/*  Constants                                                          */
/* ------------------------------------------------------------------ */

const CIRCUMFERENCE = 2 * Math.PI * 16

/* ------------------------------------------------------------------ */
/*  Types                                                              */
/* ------------------------------------------------------------------ */

export type ProgressSize = 'sm' | 'md' | 'lg'

/* ------------------------------------------------------------------ */
/*  Linear Progress                                                    */
/* ------------------------------------------------------------------ */

const trackVariants = cva('relative w-full overflow-hidden rounded-full bg-surface-secondary', {
  variants: {
    size: {
      sm: 'h-1',
      md: 'h-2',
      lg: 'h-3',
    },
  },
  defaultVariants: {
    size: 'md',
  },
})

export interface ProgressProps extends React.ComponentProps<'div'> {
  /** Progress value 0-100. Omit for indeterminate. */
  value?: number | null
  /** Size variant. */
  size?: ProgressSize
  /** Custom label text. Defaults to percentage. */
  label?: string
  /** Show the label text beside the bar. */
  showLabel?: boolean
  /** Custom color class applied to the indicator. */
  indicatorClassName?: string
  /**
   * Optional muted caption rendered on a new line below the bar.
   * Useful for ETA, throughput, or step counters.
   */
  secondaryLabel?: string
}

function Progress({
  className,
  value,
  size = 'md',
  label,
  showLabel = false,
  indicatorClassName,
  secondaryLabel,
  ...props
}: ProgressProps) {
  const isIndeterminate = value === null || value === undefined
  const clamped = isIndeterminate ? 0 : Math.min(100, Math.max(0, value))
  const displayLabel = label ?? (isIndeterminate ? '' : `${String(clamped)}%`)

  return (
    <div data-slot="progress" className={cn('flex w-full flex-col gap-1', className)} {...props}>
      <div className="flex w-full items-center gap-3">
        <div
          role="progressbar"
          aria-valuemin={0}
          aria-valuemax={100}
          aria-valuenow={isIndeterminate ? undefined : clamped}
          className={trackVariants({ size })}
        >
          <div
            data-slot="progress-indicator"
            className={cn(
              'h-full rounded-full bg-primary transition-all duration-500 ease-out',
              isIndeterminate && 'animate-progress-indeterminate w-1/3',
              indicatorClassName
            )}
            style={isIndeterminate ? undefined : { width: `${String(clamped)}%` }}
          />
        </div>
        {showLabel && displayLabel && (
          <span className="shrink-0 text-xs tabular-nums text-foreground-secondary">
            {displayLabel}
          </span>
        )}
      </div>
      {secondaryLabel && (
        <span data-slot="progress-secondary-label" className="text-xs text-muted-foreground">
          {secondaryLabel}
        </span>
      )}
    </div>
  )
}

/* ------------------------------------------------------------------ */
/*  Circular Progress                                                  */
/* ------------------------------------------------------------------ */

const circularSizes: Record<
  ProgressSize,
  { size: number; strokeWidth: number; textClass: string }
> = {
  sm: { size: 28, strokeWidth: 3, textClass: 'text-[8px]' },
  md: { size: 40, strokeWidth: 3, textClass: 'text-[10px]' },
  lg: { size: 56, strokeWidth: 4, textClass: 'text-xs' },
}

export interface CircularProgressProps extends React.ComponentProps<'div'> {
  /** Progress value 0-100. Omit for indeterminate. */
  value?: number | null
  size?: ProgressSize
  /** Custom label text. Defaults to percentage. */
  label?: string
  /** Show the label text inside the circle. */
  showLabel?: boolean
  /** Custom color class applied to the progress stroke. */
  indicatorClassName?: string
}

function CircularProgress({
  className,
  value,
  size = 'md',
  label,
  showLabel = false,
  indicatorClassName,
  ...props
}: CircularProgressProps) {
  const isIndeterminate = value === null || value === undefined
  const clamped = isIndeterminate ? 0 : Math.min(100, Math.max(0, value))
  const displayLabel = label ?? (isIndeterminate ? '' : `${String(clamped)}%`)
  const offset = isIndeterminate ? CIRCUMFERENCE * 0.75 : CIRCUMFERENCE * (1 - clamped / 100)
  const dims = circularSizes[size]

  return (
    <div
      data-slot="circular-progress"
      role="progressbar"
      aria-valuemin={0}
      aria-valuemax={100}
      aria-valuenow={isIndeterminate ? undefined : clamped}
      className={cn('relative inline-flex items-center justify-center', className)}
      style={{ width: dims.size, height: dims.size }}
      {...props}
    >
      <svg
        viewBox="0 0 36 36"
        className={cn('size-full -rotate-90', isIndeterminate && 'animate-spin')}
      >
        {/* Background circle */}
        <circle
          cx="18"
          cy="18"
          r="16"
          fill="none"
          strokeWidth={dims.strokeWidth}
          className="stroke-surface-secondary"
        />
        {/* Progress circle */}
        <circle
          cx="18"
          cy="18"
          r="16"
          fill="none"
          strokeWidth={dims.strokeWidth}
          strokeLinecap="round"
          strokeDasharray={CIRCUMFERENCE}
          strokeDashoffset={offset}
          className={cn(
            'stroke-primary transition-[stroke-dashoffset] duration-500 ease-out',
            indicatorClassName
          )}
        />
      </svg>
      {showLabel && displayLabel && (
        <span
          className={cn(
            'absolute font-medium tabular-nums text-foreground-secondary',
            dims.textClass
          )}
        >
          {displayLabel}
        </span>
      )}
    </div>
  )
}

export { Progress, CircularProgress }
