"use client"

import { Check } from "lucide-react"
import * as React from "react"

import { cn } from "../../../lib/utils"

// ─────────────────────────────────────────────────────────────────────────────
// Types
// ─────────────────────────────────────────────────────────────────────────────

interface CheckboxGroupContextValue {
  value: string[]
  onValueChange: (value: string[]) => void
  disabled: boolean
  name?: string
}

const CheckboxGroupContext = React.createContext<CheckboxGroupContextValue | null>(null)

function useCheckboxGroupContext(consumerName: string) {
  const context = React.useContext(CheckboxGroupContext)
  if (!context) {
    throw new Error(`\`${consumerName}\` must be used within \`CheckboxGroup\``)
  }
  return context
}

// ─────────────────────────────────────────────────────────────────────────────
// CheckboxGroup Root
// ─────────────────────────────────────────────────────────────────────────────

interface CheckboxGroupProps extends React.ComponentProps<"div"> {
  value?: string[]
  defaultValue?: string[]
  onValueChange?: (value: string[]) => void
  disabled?: boolean
  name?: string
}

function CheckboxGroup({
  className,
  value: valueProp,
  defaultValue,
  onValueChange,
  disabled = false,
  name,
  ...props
}: CheckboxGroupProps) {
  const isControlled = valueProp !== undefined
  const [uncontrolledValue, setUncontrolledValue] = React.useState<string[]>(defaultValue ?? [])

  const value = isControlled ? valueProp : uncontrolledValue

  const handleValueChange = React.useCallback(
    (nextValue: string[]) => {
      if (!isControlled) {
        setUncontrolledValue(nextValue)
      }
      onValueChange?.(nextValue)
    },
    [isControlled, onValueChange],
  )

  const contextValue = React.useMemo<CheckboxGroupContextValue>(
    () => ({
      value,
      onValueChange: handleValueChange,
      disabled,
      name,
    }),
    [value, handleValueChange, disabled, name],
  )

  return (
    <CheckboxGroupContext.Provider value={contextValue}>
      <div
        data-slot="checkbox-group"
        data-disabled={disabled ? "" : undefined}
        className={cn("peer flex flex-col gap-3.5", className)}
        {...props}
      />
    </CheckboxGroupContext.Provider>
  )
}

// ─────────────────────────────────────────────────────────────────────────────
// CheckboxGroupLabel
// ─────────────────────────────────────────────────────────────────────────────

function CheckboxGroupLabel({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="checkbox-group-label"
      className={cn(
        "text-foreground/70 text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
        className,
      )}
      {...props}
    />
  )
}

// ─────────────────────────────────────────────────────────────────────────────
// CheckboxGroupList
// ─────────────────────────────────────────────────────────────────────────────

interface CheckboxGroupListProps extends React.ComponentProps<"div"> {
  orientation?: "horizontal" | "vertical"
}

function CheckboxGroupList({
  className,
  orientation = "vertical",
  ...props
}: CheckboxGroupListProps) {
  return (
    <div
      data-slot="checkbox-group-list"
      data-orientation={orientation}
      className={cn(
        "flex gap-3",
        orientation === "horizontal" ? "flex-row" : "flex-col",
        className,
      )}
      {...props}
    />
  )
}

// ─────────────────────────────────────────────────────────────────────────────
// CheckboxGroupItem
// ─────────────────────────────────────────────────────────────────────────────

interface CheckboxGroupItemProps extends Omit<React.ComponentProps<"button">, "value"> {
  value: string
  disabled?: boolean
}

function CheckboxGroupItem({
  className,
  children,
  value,
  disabled: disabledProp,
  onClick,
  ...props
}: CheckboxGroupItemProps) {
  const context = useCheckboxGroupContext("CheckboxGroupItem")
  const isDisabled = disabledProp || context.disabled
  const isChecked = context.value.includes(value)

  const handleClick = React.useCallback(
    (event: React.MouseEvent<HTMLButtonElement>) => {
      onClick?.(event)
      if (isDisabled) return

      const nextValue = isChecked
        ? context.value.filter((v) => v !== value)
        : [...context.value, value]

      context.onValueChange(nextValue)
    },
    [onClick, isDisabled, isChecked, context, value],
  )

  return (
    <label
      className={cn(
        "flex w-fit select-none items-center gap-2 text-sm leading-none",
        "has-data-disabled:cursor-not-allowed has-data-disabled:opacity-50",
      )}
    >
      <button
        type="button"
        role="checkbox"
        aria-checked={isChecked}
        data-slot="checkbox-group-item"
        data-state={isChecked ? "checked" : "unchecked"}
        data-disabled={isDisabled ? "" : undefined}
        disabled={isDisabled}
        onClick={handleClick}
        className={cn(
          "size-4 shrink-0 rounded-sm border border-primary shadow-sm",
          "focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring",
          "data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
          className,
        )}
        {...props}
      >
        {isChecked && (
          <span className="flex items-center justify-center text-current">
            <Check className="size-3.5" />
          </span>
        )}
      </button>
      {children}
    </label>
  )
}

// ─────────────────────────────────────────────────────────────────────────────
// CheckboxGroupDescription
// ─────────────────────────────────────────────────────────────────────────────

function CheckboxGroupDescription({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="checkbox-group-description"
      className={cn(
        "text-[0.8rem] text-muted-foreground leading-none",
        className,
      )}
      {...props}
    />
  )
}

// ─────────────────────────────────────────────────────────────────────────────
// CheckboxGroupMessage
// ─────────────────────────────────────────────────────────────────────────────

function CheckboxGroupMessage({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="checkbox-group-message"
      className={cn(
        "text-[0.8rem] text-muted-foreground leading-none",
        className,
      )}
      {...props}
    />
  )
}

export {
  CheckboxGroup,
  CheckboxGroupDescription,
  CheckboxGroupItem,
  CheckboxGroupLabel,
  CheckboxGroupList,
  CheckboxGroupMessage,
}
export type { CheckboxGroupProps, CheckboxGroupItemProps, CheckboxGroupListProps }
