<template>
  <div class="cpRadio">
    <label
      v-for="({ label, value, description, additionalData, disabled }, index) in options"
      :key="getRadioId(index)"
      class="cpRadio__item"
      :class="computedClasses"
      :for="getRadioId(index)"
    >
      <input
        :id="getRadioId(index)"
        :autofocus="autofocus"
        :checked="isActive(value)"
        :disabled="disabled"
        :name="groupName"
        type="radio"
        :value="value"
        @input="onChange(value)"
      />
      <span class="cpRadio__label">{{ label }}</span>
      <span class="cpRadio__description">{{ description }}</span>
      <span class="cpRadio__additionalData">{{ additionalData }}</span>
    </label>
  </div>
</template>

<script setup lang="ts">
import { computed, useId } from 'vue'

import { ToggleColors } from '@/constants'
import { capitalizeFirstLetter } from '@/helpers'

interface RadioOption {
  additionalData?: string
  description?: string
  disabled?: boolean
  label: string
  value: string
}

interface Props {
  autofocus?: boolean
  color?: ToggleColors
  groupName?: string
  modelValue: string
  options: RadioOption[]
}

interface Emits {
  (e: 'update:modelValue', value: string): void
}

const props = withDefaults(defineProps<Props>(), {
  groupName: '',
  color: 'blue',
  autofocus: false,
})

const emit = defineEmits<Emits>()

const radioUniqueId = useId()

const onChange = (value: string): void => emit('update:modelValue', value)

const getRadioId = (index: number): string => `${radioUniqueId}${index}`

const isActive = (value: string): boolean => value === props.modelValue

const computedClasses = computed(() => `cpRadio--is${capitalizeFirstLetter(props.color)}`)
</script>

<style lang="scss">
@mixin cp-radio-style($color, $className) {
  &--is#{$className}:has(input:checked) {
    border-color: $color;
  }

  &--is#{$className} input:checked {
    border-color: $color;
    background-color: $color;

    & ~ .cpRadio__label,
    & ~ .cpRadio__additionalData {
      color: $color;
    }
  }

  &--is#{$className}:hover,
  &--is#{$className}:focus-within {
    border-color: $color;
  }

  &--is#{$className}:focus-within {
    box-shadow: 0 0 0 var(--cp-dimensions-1) rgba($color, 0.1);
  }
}

.cpRadio {
  $cp-radio-base-width: var(--cp-dimensions-5);

  display: flex;
  flex-direction: column;
  gap: var(--cp-spacing-lg);

  &__item {
    position: relative;
    display: grid;
    width: 100%;
    align-items: center;
    padding: var(--cp-spacing-xl) var(--cp-spacing-lg);
    border: var(--cp-dimensions-0_25) solid var(--cp-border-soft);
    border-radius: var(--cp-radius-md-lg);
    gap: 0 var(--cp-spacing-lg);
    grid-template-columns: min-content 1fr;
    grid-template-rows: auto auto auto;

    &:not(:has(input:disabled)),
    &:not(:has(input:disabled)) * {
      cursor: pointer;
    }

    &:has(input:disabled) {
      border-color: var(--cp-border-disabled);
      background-color: var(--cp-background-disabled);
      color: var(--cp-foreground-disabled);

      &,
      * {
        cursor: not-allowed;
      }

      &:hover,
      &:focus,
      &:has(input:checked) {
        border-color: var(--cp-border-disabled);
        box-shadow: none;
      }
    }
  }

  .cpRadio__label {
    grid-column: 2;
    grid-row: 1;
  }

  .cpRadio__description {
    grid-column: 2;
    grid-row: 2;
  }

  .cpRadio__additionalData {
    margin-left: 0;
    grid-column: 2;
    grid-row: 3;
    text-align: left;
  }

  @include cp-radio-style(var(--cp-foreground-accent-primary), 'Accent');
  @include cp-radio-style(var(--cp-foreground-blue-primary), 'Blue');
  @include cp-radio-style(var(--cp-foreground-accent-primary), 'Purple'); // TODO: Sould be replace by ACCENT

  input {
    width: $cp-radio-base-width;
    height: $cp-radio-base-width;
    align-self: center;
    padding: 25%;
    border: var(--cp-dimensions-0_25) solid var(--cp-border-soft);
    border-radius: var(--cp-radius-full);
    appearance: none;
    grid-column: 1;
    grid-row: 1 / -1;
    transition: transform 0.1s linear;

    &__label,
    &__description {
      line-height: 1.3;
      text-transform: capitalize;
    }

    &__label,
    &__additionalData {
      font-weight: 500;
    }

    &__description,
    &__additionalData {
      color: var(--cp-text-secondary);
    }

    &__label {
      white-space: nowrap;
    }

    &__description:empty {
      display: none;
    }

    &__additionalData:empty {
      display: none;
    }

    &::before {
      display: flex;
      width: 100%;
      height: 100%;
      border-radius: var(--cp-radius-full);
      background-color: var(--cp-background-primary);
      content: '';
      transform: scale(0);
      transition: transform 0.15s linear;
    }

    &:active:not(:disabled) {
      transform: scale(0.8);
    }

    &:checked::before {
      transform: scale(1);
    }

    &:checked:disabled {
      border-color: var(--cp-border-disabled);
      background-color: var(--cp-background-disabled);
    }

    &:checked:disabled::before {
      background-color: var(--cp-foreground-disabled);
    }

    &:checked:disabled ~ .cpRadio__label,
    &:checked:disabled ~ .cpRadio__additionalData {
      color: var(--cp-foreground-disabled);
    }
  }
}

@media (min-width: 768px) {
  .cpRadio {
    display: grid;
    gap: var(--cp-spacing-lg) var(--cp-spacing-lg);
    grid-template-columns: min-content max-content minmax(0, 1fr) auto;
  }

  .cpRadio__item {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    grid-template-rows: auto;
    row-gap: 0;

    input {
      align-self: center;
      grid-column: auto;
      grid-row: auto;
    }

    .cpRadio__label {
      grid-column: auto;
      grid-row: auto;
    }

    .cpRadio__description {
      min-width: 0;
      grid-column: auto;
      grid-row: auto;
    }

    .cpRadio__additionalData {
      margin-left: var(--cp-spacing-xl);
      grid-column: auto;
      grid-row: auto;
      text-align: right;
    }
  }
}
</style>
