import { forwardRef } from 'react'
import type {
  ButtonHTMLAttributes,
  FormHTMLAttributes,
  HTMLAttributes,
  LabelHTMLAttributes,
  ReactNode,
  SelectHTMLAttributes,
  TextareaHTMLAttributes,
  InputHTMLAttributes,
} from 'react'

function joinClasses(...classes: Array<string | false | null | undefined>) {
  return classes.filter(Boolean).join(' ')
}

const baseControlClass =
  'w-full rounded-xl border bg-white text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-500 focus:border-[var(--brand-green)] focus:ring-4 focus:ring-[color-mix(in_srgb,var(--brand-green)_16%,transparent)] disabled:cursor-not-allowed disabled:bg-zinc-100 disabled:text-zinc-500 dark:bg-zinc-950 dark:text-zinc-50 dark:placeholder:text-zinc-500 dark:disabled:bg-zinc-900 dark:disabled:text-zinc-500'

function controlClass(hasError?: boolean, className?: string) {
  return joinClasses(
    baseControlClass,
    hasError
      ? 'border-red-500 dark:border-red-400'
      : 'border-zinc-300 dark:border-zinc-700',
    className,
  )
}

export function FormPanel({
  children,
  className,
  ...props
}: FormHTMLAttributes<HTMLFormElement>) {
  return (
    <form
      className={joinClasses(
        'space-y-8 rounded-lg border border-zinc-200 bg-white p-5 shadow-sm dark:border-zinc-800 dark:bg-zinc-900 sm:p-7',
        className,
      )}
      {...props}
    >
      {children}
    </form>
  )
}

export function FormSection({
  title,
  children,
  className,
}: {
  title?: string
  children: ReactNode
  className?: string
}) {
  return (
    <section className={joinClasses('space-y-4', className)}>
      {title ? (
        <h2 className="text-lg font-semibold text-zinc-950 dark:text-white">
          {title}
        </h2>
      ) : null}
      {children}
    </section>
  )
}

export const FieldGroup = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
  function FieldGroup({ children, className, ...props }, ref) {
    return (
      <div ref={ref} className={joinClasses('space-y-2', className)} {...props}>
        {children}
      </div>
    )
  },
)

export function FieldGrid({ children, className }: { children: ReactNode; className?: string }) {
  return (
    <div className={joinClasses('grid gap-4 sm:grid-cols-2', className)}>
      {children}
    </div>
  )
}

export function FieldLabel({
  children,
  required: _required,
  className,
  ...props
}: LabelHTMLAttributes<HTMLLabelElement> & {
  required?: boolean
}) {
  void _required

  return (
    <label
      className={joinClasses('block text-sm font-medium text-zinc-700 dark:text-zinc-400', className)}
      {...props}
    >
      {children}
    </label>
  )
}

export function FormTooltip({
  id,
  text,
  className,
}: {
  id: string
  text: string
  className?: string
}) {
  return (
    <span className={joinClasses('group relative inline-flex align-middle', className)}>
      <button
        type="button"
        aria-describedby={id}
        aria-label={text}
        className="inline-flex h-5 w-5 items-center justify-center rounded-full border border-zinc-300 bg-white text-xs font-semibold text-zinc-600 shadow-sm transition hover:border-zinc-400 hover:text-zinc-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-green)] dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-300 dark:hover:border-zinc-500 dark:hover:text-white"
      >
        ?
      </button>
      <span
        id={id}
        role="tooltip"
        className="pointer-events-none absolute left-1/2 top-7 z-20 hidden w-72 -translate-x-1/2 rounded-md border border-zinc-200 bg-white px-3 py-2 text-xs font-normal leading-5 text-zinc-700 shadow-lg group-focus-within:block group-hover:block dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-200"
      >
        {text}
      </span>
    </span>
  )
}

export function LabelWithTooltip({
  children,
  tooltipId,
  tooltipText,
  htmlFor,
  required,
  className,
}: {
  children: ReactNode
  tooltipId: string
  tooltipText: string
  htmlFor?: string
  required?: boolean
  className?: string
}) {
  return (
    <div className="flex items-center gap-2">
      <FieldLabel htmlFor={htmlFor} required={required} className={className}>
        {children}
      </FieldLabel>
      <FormTooltip id={tooltipId} text={tooltipText} />
    </div>
  )
}

export function FieldHint({
  children,
  tone = 'neutral',
  className,
}: {
  children: ReactNode
  tone?: 'neutral' | 'error'
  className?: string
}) {
  return (
    <p
      className={joinClasses(
        'text-xs',
        tone === 'error'
          ? 'font-medium text-red-700 dark:text-red-300'
          : 'text-zinc-600 dark:text-zinc-400',
        className,
      )}
    >
      {children}
    </p>
  )
}

export function TextField({
  hasError,
  className,
  ...props
}: InputHTMLAttributes<HTMLInputElement> & {
  hasError?: boolean
}) {
  return <input className={controlClass(hasError, joinClasses('h-12 px-4 text-sm', className))} {...props} />
}

export function SelectField({
  hasError,
  placeholderValue,
  className,
  children,
  ...props
}: SelectHTMLAttributes<HTMLSelectElement> & {
  hasError?: boolean
  placeholderValue?: string
}) {
  const selectedValue = props.value ?? props.defaultValue
  const isPlaceholderSelected = placeholderValue !== undefined && selectedValue === placeholderValue

  return (
    <select
      className={controlClass(
        hasError,
        joinClasses(
          'form-select-brand h-11 appearance-none rounded-xl py-0 pl-3.5 pr-9 text-sm [-webkit-appearance:none]',
          placeholderValue === '' && 'form-select-placeholder',
          className,
        ),
      )}
      data-placeholder-selected={isPlaceholderSelected ? 'true' : undefined}
      {...props}
    >
      {children}
    </select>
  )
}

export function TextareaField({
  hasError,
  className,
  ...props
}: TextareaHTMLAttributes<HTMLTextAreaElement> & {
  hasError?: boolean
}) {
  return (
    <textarea
      className={controlClass(
        hasError,
        joinClasses('min-h-24 resize-y px-4 py-3 text-sm leading-5', className),
      )}
      {...props}
    />
  )
}

export function RangeField({
  className,
  ...props
}: InputHTMLAttributes<HTMLInputElement>) {
  return (
    <input
      type="range"
      className={joinClasses('h-2 flex-1 accent-[var(--brand-green)]', className)}
      {...props}
    />
  )
}

export function CheckboxField({
  className,
  ...props
}: InputHTMLAttributes<HTMLInputElement>) {
  return (
    <input
      type="checkbox"
      className={joinClasses(
        'mt-0.5 h-5 w-5 rounded border-zinc-300 text-[var(--brand-green)] accent-[var(--brand-green)] dark:border-zinc-600',
        className,
      )}
      {...props}
    />
  )
}

export function FormActions({ children, className }: { children: ReactNode; className?: string }) {
  return (
    <div className={joinClasses('border-t border-zinc-200 pt-6 dark:border-zinc-800', className)}>
      {children}
    </div>
  )
}

export function PrimaryButton({
  className,
  children,
  loading,
  disabled,
  ...props
}: ButtonHTMLAttributes<HTMLButtonElement> & {
  loading?: boolean
}) {
  return (
    <button
      className={joinClasses(
        'inline-flex items-center justify-center gap-2 rounded-xl bg-[var(--brand-green)] px-4 py-3 text-sm font-semibold text-white shadow-sm transition hover:bg-[var(--brand-green-hover)] active:bg-[var(--brand-green-active)] disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[color-mix(in_srgb,var(--brand-green)_28%,transparent)]',
        className,
      )}
      disabled={disabled || loading}
      aria-busy={loading || undefined}
      {...props}
    >
      {loading ? (
        <span
          aria-hidden="true"
          className="h-4 w-4 rounded-full border-2 border-white/70 border-t-transparent animate-spin"
        />
      ) : null}
      {children}
    </button>
  )
}

export function SecondaryButton({
  className,
  children,
  ...props
}: ButtonHTMLAttributes<HTMLButtonElement>) {
  return (
    <button
      className={joinClasses(
        'rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm font-semibold text-zinc-800 shadow-sm transition hover:bg-zinc-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-100 dark:hover:bg-zinc-800',
        className,
      )}
      {...props}
    >
      {children}
    </button>
  )
}
