import type { JSX, ReactNode } from 'react'

export type FieldLabelMode = 'above' | 'inline' | 'hidden'

export interface FieldProps {
  label: string
  labelMode?: FieldLabelMode
  hint?: string
  error?: string
}

const CONTROL_BASE =
  'min-w-0 flex-1 rounded-md border bg-surface-raised px-3 text-sm text-fg placeholder:text-fg-subtle focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:cursor-not-allowed disabled:opacity-60'

export function fieldControlClass(invalid: boolean, extra: string): string {
  return [CONTROL_BASE, invalid ? 'border-danger' : 'border-border focus-visible:border-accent', extra].join(' ')
}

export function describedBy(hintId: string | null, errorId: string | null): string | undefined {
  const ids = [hintId, errorId].filter((id): id is string => id !== null)
  return ids.length > 0 ? ids.join(' ') : undefined
}

const LABEL_CLASS = 'text-xs font-medium text-fg-muted'

export function FieldShell(props: {
  controlId: string
  label: string
  labelMode: FieldLabelMode
  hint?: string
  hintId?: string
  error?: string
  errorId?: string
  trailing?: ReactNode
  children: ReactNode
}): JSX.Element {
  const label = (
    <label
      htmlFor={props.controlId}
      className={props.labelMode === 'hidden' ? 'sr-only' : `${LABEL_CLASS} shrink-0`}
    >
      {props.label}
    </label>
  )
  const controlRow = (
    <div className="flex min-w-0 flex-1 items-center gap-2">
      {props.children}
      {props.trailing}
    </div>
  )

  if (props.labelMode === 'inline') {
    return (
      <div className="flex min-w-0 flex-1 flex-col gap-1">
        <div className="flex min-w-0 items-center gap-2">
          {label}
          {controlRow}
        </div>
        <FieldMessages hintId={props.hintId} hint={props.hint} errorId={props.errorId} error={props.error} />
      </div>
    )
  }

  return (
    <div className="flex min-w-0 flex-col gap-1">
      {label}
      {controlRow}
      <FieldMessages hintId={props.hintId} hint={props.hint} errorId={props.errorId} error={props.error} />
    </div>
  )
}

function FieldMessages(props: {
  hint?: string
  hintId?: string
  error?: string
  errorId?: string
}): JSX.Element | null {
  if (props.hint === undefined && props.error === undefined) return null
  return (
    <>
      {props.hint !== undefined && (
        <p id={props.hintId} className="text-xs text-fg-subtle">
          {props.hint}
        </p>
      )}
      {props.error !== undefined && (
        <p id={props.errorId} className="text-xs font-medium text-danger">
          {props.error}
        </p>
      )}
    </>
  )
}
