<template>
  <div
    :key="'product-field-' + productType"
    :class="[
      'ivyforms-field',
      'ivyforms-product-field',
      'ivyforms-product-field--field-' + field.id,
      field.cssClasses,
    ]"
  >
    <IvyFormItem
      :label="field.hideLabel ? '' : field.label"
      :required="field.required"
      :error="error"
      :prop="field.type + '_' + field.fieldIndex"
      :show-info="false"
      :label-position="field.labelPosition === 'default' ? 'top' : field.labelPosition || 'top'"
    >
      <template v-if="productType === 'select'">
        <IvySelectInput
          :id="fieldId"
          v-model="localStringValue"
          :placeholder="field.placeholder || ''"
          :disabled="disabled || field.readOnly"
          :required="field.required"
          :filterable="!!field.enableSearch"
          :aria-label="field.label"
          secondary
          class="ivyforms-product-field__select"
          popper-class="ivyforms-product-field__select-popper"
        >
          <template #label="{ label: slotLabel }">
            <span :class="productSpreadRowClass">
              <span :class="productRowLabelClass">{{ slotLabel }}</span>
              <span
                v-if="
                  selectedProductSelectOption &&
                  showProductOptionPrice(productConfig, selectedProductSelectOption)
                "
                :class="productRowPriceClass"
              >
                {{
                  formatProductPriceWithCurrencySuffix(
                    getProductOptionPriceRaw(productConfig, selectedProductSelectOption),
                    resolvedCurrencyCode,
                  )
                }}
              </span>
            </span>
          </template>
          <IvySelectOption
            v-for="option in displayOptions"
            :key="String(option.id ?? option.value)"
            :value="option.value"
            :label="option.label"
            secondary
          >
            <span :class="productSpreadRowClass">
              <span :class="productRowLabelClass">{{ option.label }}</span>
              <span
                v-if="showProductOptionPrice(productConfig, option)"
                :class="productRowPriceClass"
              >
                {{
                  formatProductPriceWithCurrencySuffix(
                    getProductOptionPriceRaw(productConfig, option),
                    resolvedCurrencyCode,
                  )
                }}
              </span>
            </span>
          </IvySelectOption>
        </IvySelectInput>
      </template>

      <template v-else-if="productType === 'checkbox'">
        <IvyCheckboxGroup
          :id="fieldId"
          v-model="localArrayValue"
          :disabled="disabled"
          :class="[
            'ivyforms-product-field__checkbox-group',
            'ivyforms-flex',
            'ivyforms-flex-direction-column',
            'ivyforms-gap-8',
            'ivyforms-align-items-start',
            groupLayoutClass,
          ]"
          role="group"
          :aria-required="field.required ? 'true' : undefined"
          :aria-readonly="field.readOnly ? 'true' : undefined"
        >
          <IvyCheckbox
            v-for="option in displayOptions"
            :id="`${fieldId}_${option.id ?? option.value}`"
            :key="option.id || option.value"
            :value="option.value"
            :aria-label="String(option.label || field.label)"
            priority="secondary"
            type="checkmark"
            class="ivyforms-width-100"
          >
            <span :class="productSpreadRowClass">
              <span :class="productRowLabelClass">{{ option.label }}</span>
              <span
                v-if="showProductOptionPrice(productConfig, option)"
                :class="productRowPriceClass"
              >
                {{
                  formatProductPriceWithCurrencySuffix(
                    getProductOptionPriceRaw(productConfig, option),
                    resolvedCurrencyCode,
                  )
                }}
              </span>
            </span>
          </IvyCheckbox>
        </IvyCheckboxGroup>
      </template>

      <template v-else-if="productType === 'radio'">
        <IvyRadioGroup
          :id="fieldId"
          v-model="localStringValue"
          direction="vertical"
          :class="['ivyforms-product-field__radio-group', 'ivyforms-width-100', groupLayoutClass]"
          :aria-label="field.label"
          :disabled="disabled"
        >
          <IvyRadio
            v-for="option in displayOptions"
            :key="String(option.id ?? option.value)"
            priority="secondary"
            :value="option.value"
            :disabled="disabled || field.readOnly"
            class="ivyforms-product-field__radio ivyforms-width-100"
            :class="{ 'ivyforms-product-field__radio--button': choiceLayout === 'button' }"
          >
            <span :class="productSpreadRowClass">
              <span :class="productRowLabelClass">{{ option.label }}</span>
              <span
                v-if="showProductOptionPrice(productConfig, option)"
                :class="productRowPriceClass"
              >
                {{
                  formatProductPriceWithCurrencySuffix(
                    getProductOptionPriceRaw(productConfig, option),
                    resolvedCurrencyCode,
                  )
                }}
              </span>
            </span>
          </IvyRadio>
        </IvyRadioGroup>
      </template>

      <template v-else-if="productType === 'single'">
        <div
          class="ivyforms-product-field__single ivyforms-flex ivyforms-flex-direction-column ivyforms-gap-8 ivyforms-width-100 ivyforms-align-self-stretch"
        >
          <div v-if="showSingleTopRow" :class="productSpreadRowWrapClass">
            <span :class="productRowLabelClass">{{ singleGridLeftText }}</span>
            <span
              v-if="singlePriceOnRight"
              class="ivyforms-flex ivyforms-align-items-baseline ivyforms-gap-8 ivyforms-flex-shrink-0 ivyforms-justify-content-end ivyforms-ml-auto text-align-right ivyforms-whitespace-nowrap"
            >
              <span v-if="amountLabelText" class="regular-14 text-secondary">{{
                amountLabelText
              }}</span>
              <span class="medium-16 text-primary">{{ singlePaymentFormatted }}</span>
            </span>
          </div>
          <span v-if="amountLabelText && !singlePriceOnRight" class="regular-14 text-secondary">{{
            amountLabelText
          }}</span>
          <span v-if="singlePaymentBelow" class="medium-16 text-primary">{{
            singlePaymentFormatted
          }}</span>
        </div>
      </template>

      <template v-else-if="productType === 'user_defined'">
        <IvyTextInput
          :id="fieldId"
          v-model="localStringValue"
          :placeholder="field.placeholder || ''"
          :disabled="disabled"
          :readonly="field.readOnly"
          secondary
          class="ivyforms-width-100"
        />
      </template>
      <FieldDescriptionDisplay :html="field.description" />
    </IvyFormItem>
  </div>
</template>

<script setup lang="ts">
import { computed, inject, ref, watch, type ComputedRef } from 'vue'
import type { Field, Choice } from '@/types/field'
import IvyFormItem from '@/views/_components/form/IvyFormItem.vue'
import IvyRadioGroup from '@/views/_components/radio/IvyRadioGroup.vue'
import IvyRadio from '@/views/_components/radio/IvyRadio.vue'
import IvySelectInput from '@/views/_components/input/IvySelectInput.vue'
import IvySelectOption from '@/views/_components/input/IvySelectOption.vue'
import IvyCheckboxGroup from '@/views/_components/checkbox/IvyCheckboxGroup.vue'
import IvyCheckbox from '@/views/_components/checkbox/IvyCheckbox.vue'
import IvyTextInput from '@/views/_components/input/IvyTextInput.vue'
import { useLabels } from '@/composables/useLabels'
import {
  formatProductPriceWithCurrencySuffix,
  getProductOptionPriceRaw,
  parseProductFieldConfig,
  showProductOptionPrice,
} from '@/utils/productFieldConfig'
import {
  DEFAULT_CURRENCY_CODE,
  type CurrencyCode,
  isCurrencyCode,
} from '@/constants/supportedCurrencies'

/** Flex row: label left, value right (select trigger/options, choice rows, single header). */
const productSpreadRowClass = [
  'ivyforms-flex',
  'ivyforms-flex-direction-row',
  'ivyforms-align-items-center',
  'ivyforms-justify-content-between',
  'ivyforms-gap-16',
  'ivyforms-width-100',
  'ivyforms-min-width-0',
].join(' ')

/** Spread row with wrap + row gap for the single-product title line. */
const productSpreadRowWrapClass = `${productSpreadRowClass} ivyforms-flex-wrap-wrap ivyforms-gap-row-8`

const productRowLabelClass =
  'ivyforms-flex-1 ivyforms-min-width-0 ivyforms-word-break regular-16 text-primary'

const productRowPriceClass =
  'ivyforms-flex-shrink-0 text-align-right ivyforms-whitespace-nowrap regular-16 text-primary'

interface FieldProps {
  modelValue: string | number | string[] | null | undefined
  field: Field
  disabled?: boolean
  error?: string
}

const props = withDefaults(defineProps<FieldProps>(), {
  modelValue: '',
  disabled: false,
  error: '',
})

const emit = defineEmits(['update:modelValue'])

const { getLabel } = useLabels()

const paymentCurrencyInjected = inject<ComputedRef<CurrencyCode> | undefined>(
  'ivyformsPaymentCurrencyCode',
  undefined,
)

const resolvedCurrencyCode = computed<CurrencyCode>(() => {
  const v = paymentCurrencyInjected?.value
  return typeof v === 'string' && isCurrencyCode(v) ? v : DEFAULT_CURRENCY_CODE
})

const fieldId = computed(() => `field_${props.field.fieldIndex}`)
const clearFieldError = inject<(fieldKey: string) => void>('clearFieldError', () => {})
const fieldKey = computed(() => props.field.type + '_' + props.field.fieldIndex)

const productConfig = computed(() => parseProductFieldConfig(props.field))
const productType = computed(() => productConfig.value.productType)
const choiceLayout = computed(() => productConfig.value.choiceLayout)

const localStringValue = ref('')
const localArrayValue = ref<string[]>([])

function toCheckboxArray(v: unknown): string[] {
  if (Array.isArray(v)) {
    return v.map((x) => String(x))
  }
  if (typeof v === 'string' && v) {
    return v
      .split(',')
      .map((s) => s.trim())
      .filter(Boolean)
  }
  return []
}

function checkboxArraysEqual(a: string[], b: string[]): boolean {
  if (a.length !== b.length) {
    return false
  }
  return a.every((val, i) => val === b[i])
}

function propsStringModel(): string {
  if (Array.isArray(props.modelValue)) {
    return props.modelValue.length > 0 ? String(props.modelValue[0]) : ''
  }
  if (props.modelValue === null || props.modelValue === undefined) {
    return ''
  }
  return String(props.modelValue)
}

function normalizeIncoming() {
  const t = productType.value
  if (t === 'checkbox') {
    const next = toCheckboxArray(props.modelValue)
    if (!checkboxArraysEqual(next, localArrayValue.value)) {
      localArrayValue.value = next
    }
    return
  }
  let next = ''
  if (Array.isArray(props.modelValue)) {
    next = props.modelValue.length > 0 ? String(props.modelValue[0]) : ''
  } else if (props.modelValue === null || props.modelValue === undefined) {
    next = ''
  } else {
    next = String(props.modelValue)
  }
  if (localStringValue.value !== next) {
    localStringValue.value = next
  }
}

const shuffled = ref<Choice[]>([])

function refreshDisplayOptions() {
  let opts = props.field.fieldOptions || []
  if (props.field.shuffleOptions) {
    opts = shuffle([...opts])
  }
  shuffled.value = opts
}

watch(
  () => [props.field.fieldOptions, props.field.shuffleOptions, props.field.htmlContent] as const,
  () => {
    refreshDisplayOptions()
    normalizeIncoming()
  },
  { deep: true, immediate: true },
)

const displayOptions = computed(() => shuffled.value)

const selectedProductSelectOption = computed(() => {
  if (productType.value !== 'select') {
    return undefined
  }
  const sv = localStringValue.value
  return displayOptions.value.find((o) => String(o.value) === String(sv))
})

function shuffle<T>(array: T[]): T[] {
  const arr = array.slice()
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[arr[i], arr[j]] = [arr[j], arr[i]]
  }
  return arr
}

watch(
  () => props.modelValue,
  () => {
    normalizeIncoming()
  },
)

watch(localStringValue, (newVal) => {
  if (productType.value === 'checkbox') {
    return
  }
  if (String(newVal) === propsStringModel()) {
    clearFieldError(fieldKey.value)
    return
  }
  emit('update:modelValue', newVal)
  clearFieldError(fieldKey.value)
})

watch(localArrayValue, (newVal) => {
  if (productType.value !== 'checkbox') {
    return
  }
  if (checkboxArraysEqual(newVal, toCheckboxArray(props.modelValue))) {
    clearFieldError(fieldKey.value)
    return
  }
  emit('update:modelValue', [...newVal])
  clearFieldError(fieldKey.value)
})

const error = computed(() => props.error || '')
const disabled = computed(() => props.disabled || props.field.readOnly)

const groupLayoutClass = computed(() => {
  if (choiceLayout.value === 'columns') {
    return `ivyforms-product-field__layout ivyforms-product-field__layout--columns ivyforms-product-field__layout--columns-${productConfig.value.columnsCount}`
  }
  if (choiceLayout.value === 'inline') {
    return 'ivyforms-product-field__layout ivyforms-product-field__layout--inline'
  }
  if (choiceLayout.value === 'button') {
    return 'ivyforms-product-field__layout ivyforms-product-field__layout--button'
  }
  return ''
})

/** Single product: title comes from default value, not leftover choice rows. */
const singleProductTitle = computed(() => {
  if (productType.value !== 'single') {
    return ''
  }
  const raw = props.field.defaultValue
  if (raw === null || raw === undefined) {
    return ''
  }
  return String(raw).trim()
})

const amountLabelText = computed(() => productConfig.value.amountLabel.trim())

const singlePaymentFormatted = computed(() =>
  formatProductPriceWithCurrencySuffix(
    productConfig.value.paymentAmount ?? '',
    resolvedCurrencyCode.value,
  ),
)

const singlePriceOnRight = computed(
  () => productConfig.value.showPriceAfterItemLabel && singlePaymentFormatted.value !== '',
)

const singleGridLeftText = computed(() => singleProductTitle.value)

const showSingleTopRow = computed(
  () => Boolean(singleProductTitle.value) || singlePriceOnRight.value,
)

const singlePaymentBelow = computed(
  () => singlePaymentFormatted.value !== '' && !singlePriceOnRight.value,
)

watch(
  () => [productType.value, singleProductTitle.value] as const,
  () => {
    if (productType.value !== 'single') {
      return
    }
    const v = singleProductTitle.value
    if (localStringValue.value !== v) {
      localStringValue.value = v
    }
    if (propsStringModel() !== v) {
      emit('update:modelValue', v)
    }
  },
  { immediate: true },
)
</script>

<style scoped lang="scss">
.ivyforms-product-field {
  :deep(.ivyforms-product-field__preview-checkbox-group .ivyforms-checkbox.el-checkbox),
  :deep(.ivyforms-product-field__checkbox-group .ivyforms-checkbox.el-checkbox) {
    width: 100%;
    max-width: 100%;
  }

  :deep(.ivyforms-product-field__preview-checkbox-group .el-checkbox__label),
  :deep(.ivyforms-product-field__checkbox-group .el-checkbox__label) {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    max-width: 100%;
  }

  :deep(.ivyforms-product-field__preview-checkbox-group .ivyforms-checkbox__label-with-tooltip),
  :deep(.ivyforms-product-field__checkbox-group .ivyforms-checkbox__label-with-tooltip) {
    display: block;
    width: 100%;
    min-width: 0;
  }

  :deep(.ivyforms-product-field__preview-radio-group .ivyforms-radio.el-radio),
  :deep(.ivyforms-product-field__radio-group .ivyforms-radio.el-radio) {
    width: 100%;
    max-width: 100%;
  }

  :deep(.ivyforms-product-field__preview-radio-group .el-radio__label),
  :deep(.ivyforms-product-field__radio-group .el-radio__label) {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    max-width: 100%;
  }

  :deep(.ivyforms-product-field__preview-radio-group .ivyforms-radio__label-with-tooltip),
  :deep(.ivyforms-product-field__radio-group .ivyforms-radio__label-with-tooltip) {
    display: block;
    width: 100%;
    min-width: 0;
  }

  :deep(.ivyforms-product-field__radio.el-radio) {
    width: 100%;
    margin-right: 0;
    align-items: center;
  }

  :deep(.ivyforms-product-field__radio--button.el-radio) {
    border: 1px solid var(--map-base-dusk-stroke--2, #c0c5cb);
    border-radius: 8px;
    padding: 8px 12px;
    background: var(--map-base-dusk-o05, rgba(139, 146, 156, 0.05));
  }

  :deep(.ivyforms-product-field__radio .el-radio__label) {
    flex: 1;
    width: 100%;
  }

  :deep(.ivyforms-product-field__layout--inline.ivyforms-product-field__checkbox-group) {
    flex-direction: row !important;
    flex-wrap: wrap;
    align-items: flex-start;
  }

  :deep(.ivyforms-product-field__layout--inline.ivyforms-product-field__radio-group) {
    flex-direction: row !important;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px;
  }

  :deep([class*='ivyforms-product-field__layout--columns-'].ivyforms-product-field__checkbox-group),
  :deep([class*='ivyforms-product-field__layout--columns-'].ivyforms-product-field__radio-group) {
    display: grid;
    gap: 8px;
  }

  :deep(.ivyforms-product-field__layout--columns-2) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  :deep(.ivyforms-product-field__layout--columns-3) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  :deep(.ivyforms-product-field__layout--columns-4) {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  :deep(.ivyforms-product-field__layout--columns-5) {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
  :deep(.ivyforms-product-field__layout--columns-6) {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  :deep(.ivyforms-product-field__layout--button.ivyforms-product-field__radio-group) {
    flex-direction: row !important;
    flex-wrap: wrap;
    gap: 8px;
  }

  :deep(.ivyforms-product-field__select .el-select__placeholder) {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
  }
}
</style>

<!-- Teleported select dropdown: scoped styles do not apply inside the popper -->
<style lang="scss">
.ivyforms-product-field__select-popper {
  .el-select-dropdown__item {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
  }
}
</style>
