import * as ProgressPrimitive from "@radix-ui/react-progress";
import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from "react";

import {
  progressIndicatorVariants,
  progressVariants
} from "./progress.variants";
import { cn } from "../lib/cn";
import type { VariantProps } from "../lib/cva";
import { createDataAttributes, createSlot } from "../lib/contracts";

function clampValue(value: number, max: number) {
  return Math.min(Math.max(value, 0), max);
}

function getState(value: number | null | undefined, max: number) {
  if (value == null) {
    return "indeterminate";
  }

  return clampValue(value, max) >= max ? "complete" : "loading";
}

function getIndicatorWidth(value: number | null | undefined, max: number) {
  if (value == null) {
    return "38%";
  }

  return `${(clampValue(value, max) / max) * 100}%`;
}

export type ProgressProps = ComponentPropsWithoutRef<typeof ProgressPrimitive.Root> &
  VariantProps<typeof progressVariants> &
  VariantProps<typeof progressIndicatorVariants>;

export const Progress = forwardRef<
  ElementRef<typeof ProgressPrimitive.Root>,
  ProgressProps
>(function Progress(
  {
    className,
    max = 100,
    size,
    tone,
    value,
    variant,
    ...props
  },
  ref
) {
  const resolvedMax = max > 0 ? max : 100;
  const state = getState(value, resolvedMax);

  return (
    <ProgressPrimitive.Root
      {...props}
      {...createSlot("root")}
      {...createDataAttributes({
        size,
        state,
        tone,
        variant
      })}
      className={cn(progressVariants({ size, tone }), className)}
      max={resolvedMax}
      ref={ref}
      value={value ?? undefined}
    >
      <ProgressPrimitive.Indicator
        {...createSlot("indicator")}
        {...createDataAttributes({
          size,
          state,
          variant
        })}
        className={cn(progressIndicatorVariants({ variant }))}
        style={{
          width: getIndicatorWidth(value, resolvedMax)
        }}
      />
    </ProgressPrimitive.Root>
  );
});
