<script setup lang="ts">
/**
 * Props-driven multi-checkbox composition. Renders one Checkbox per
 * option and stores the result as an array of selected values.
 *
 *   <CheckboxOption v-model="prefs" :options="[...]" label="Preferences" />
 */
import { computed } from "vue"
import type { SelectOptionLike } from "@/definitions/shared/select-options"
import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"
import { FieldFrame } from "@/components/ui/field-frame"

export interface CheckboxOptionProps {
  modelValue?: Array<string | number> | null
  options?: SelectOptionLike[]
  id?: string
  name?: string
  label?: string
  hideLabel?: boolean
  inline?: boolean
  required?: boolean
  readonly?: boolean
  disabled?: boolean
  helpText?: string
  errors?: string[]
}

const props = withDefaults(defineProps<CheckboxOptionProps>(), {
  errors: () => [],
  options: () => [],
})

const model = defineModel<Array<string | number> | null>("modelValue")

interface NormalisedOption {
  label: string
  value: string
  disabled: boolean
}

function normaliseOption(opt: SelectOptionLike): NormalisedOption {
  if (typeof opt === "string") {
    return { label: opt, value: opt, disabled: false }
  }
  return {
    label: opt.label,
    value: String(opt.value),
    disabled: Boolean(opt.disabled),
  }
}

const normalised = computed<NormalisedOption[]>(() =>
  (props.options ?? []).map(normaliseOption),
)

const selected = computed<string[]>(() => {
  const v = model.value
  if (!v) {
    return []
  }
  if (Array.isArray(v)) {
    return v.map((x) => String(x))
  }
  return [String(v)]
})

function isChecked(val: string): boolean {
  return selected.value.includes(val)
}

function onToggle(val: string, checked: boolean | "indeterminate"): void {
  const current = selected.value
  if (checked === true) {
    if (!current.includes(val)) {
      model.value = [...current, val]
    }
  } else {
    model.value = current.filter((v) => v !== val)
  }
}
</script>

<template>
  <FieldFrame
    :label="label"
    :required="required"
    :hide-label="hideLabel"
    :help-text="helpText"
    :errors="errors"
  >
    <div
      :class="inline ? 'flex flex-row flex-wrap gap-4' : 'grid gap-2'"
      :data-element-name="name ?? undefined"
    >
      <div
        v-for="opt in normalised"
        :key="opt.value"
        class="flex items-center gap-2"
      >
        <Checkbox
          :id="`${id ?? 'checkbox'}-${opt.value}`"
          :name="name"
          :model-value="isChecked(opt.value)"
          :disabled="opt.disabled || disabled || readonly"
          @update:model-value="(c) => onToggle(opt.value, c)"
        />
        <Label
          :for="`${id ?? 'checkbox'}-${opt.value}`"
          class="cursor-pointer"
        >
          {{ opt.label }}
        </Label>
      </div>
    </div>
  </FieldFrame>
</template>
