<template>
  <div class="cpAlert">
    <div class="cpAlert__inner" :class="dynamicClasses">
      <div class="cpAlert__icon">
        <slot name="icon">
          <cp-icon size="16" :type="alertIcon" />
        </slot>
      </div>
      <div class="cpAlert__body">
        <div class="cpAlert__content">
          <p v-if="hasTitle" class="cpAlert__title">
            <slot name="title">
              {{ title }}
            </slot>
          </p>
          <p v-if="hasContent" class="cpAlert__contentText">
            <slot>
              {{ content }}
            </slot>
          </p>
        </div>
        <div v-if="hasActions" class="cpAlert__actions">
          <div v-if="hasPrimaryAction" class="cpAlert__action">
            <slot name="primary-action">
              <cp-button
                :appearance="primaryActionAppearance"
                :color="color"
                is-square
                :size="actionsSize"
                @click="emit('primaryActionClick')"
              >
                {{ primaryActionLabel }}
              </cp-button>
            </slot>
          </div>
          <div v-if="hasSecondaryAction" class="cpAlert__action">
            <slot name="secondary-action">
              <cp-button
                :appearance="secondaryActionAppearance"
                :color="color"
                is-square
                :size="actionsSize"
                @click="emit('secondaryActionClick')"
              >
                {{ secondaryActionLabel }}
              </cp-button>
            </slot>
          </div>
        </div>
      </div>
      <div v-if="isClosable" class="cpAlert__close">
        <cp-button appearance="tertiary" :color="color" is-square size="xs" @click="emit('onClose')">
          <template #leading-icon>
            <cp-icon size="16" type="x" />
          </template>
        </cp-button>
      </div>
    </div>
  </div>
</template>

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

import type { Colors } from '@/constants'

import { capitalizeFirstLetter } from '@/helpers'

type AlertColors = Extract<Colors, 'neutral' | 'accent' | 'success' | 'warning' | 'error'>
type AlertTypes = 'expanded' | 'inline'

interface Props {
  color?: AlertColors
  content?: string
  icon?: string
  isClosable?: boolean
  primaryActionLabel?: string
  secondaryActionLabel?: string
  title?: string
  type?: AlertTypes
}

const props = withDefaults(defineProps<Props>(), {
  color: 'neutral',
  icon: undefined,
  content: undefined,
  title: undefined,
  isClosable: false,
  type: 'expanded',
  primaryActionLabel: undefined,
  secondaryActionLabel: undefined,
})

const emit = defineEmits<{
  onClose: []
  primaryActionClick: []
  secondaryActionClick: []
}>()

const slots = useSlots()

const colorProps = computed(() => {
  const defaultProps = {
    primaryActionAppearance: isExpanded.value ? 'primary' : 'secondary',
    secondaryActionAppearance: 'secondary',
  }
  return {
    neutral: {
      icon: 'dashed-circle',
      primaryActionAppearance: isExpanded.value ? 'secondary' : 'tertiary',
      secondaryActionAppearance: 'tertiary',
    },
    accent: {
      ...defaultProps,
      icon: 'info',
    },
    success: {
      ...defaultProps,
      icon: 'check',
    },
    warning: {
      ...defaultProps,
      icon: 'alert-triangle',
    },
    error: {
      ...defaultProps,
      icon: 'x-octagon',
    },
  }
})

const alertIcon = computed(() => {
  if (props.icon) return props.icon
  return colorProps.value[props.color].icon
})

const isExpanded = computed(() => props.type === 'expanded')
const hasTitle = computed(() => !!props.title || !!slots.title)
const hasContent = computed(() => isExpanded.value && (!!props.content || !!slots.default))
const hasActions = computed(() => hasPrimaryAction.value || hasSecondaryAction.value)
const hasPrimaryAction = computed(() => !!props.primaryActionLabel || !!slots['primary-action'])
const hasSecondaryAction = computed(
  () => isExpanded.value && (!!props.secondaryActionLabel || !!slots['secondary-action']),
)
const primaryActionAppearance = computed(() => colorProps.value[props.color].primaryActionAppearance)
const secondaryActionAppearance = computed(() => colorProps.value[props.color].secondaryActionAppearance)
const actionsSize = computed(() => (isExpanded.value ? 'sm' : 'xs'))

const dynamicClasses = computed(() => [
  `cpAlert--is${capitalizeFirstLetter(props.type)}`,
  `cpAlert--is${capitalizeFirstLetter(props.color)}`,
])
</script>

<style lang="scss">
.cpAlert {
  display: flex;
  width: 100%;

  &__inner {
    position: relative;
    display: flex;
    overflow: hidden;
    width: 100%;
    align-items: flex-start;
    padding: var(--cp-spacing-lg) var(--cp-spacing-lg) var(--cp-spacing-lg) var(--cp-spacing-md);
    border: 1px solid var(--cp-alert-border);
    border-radius: var(--cp-radius-md);
    margin: var(--cp-spacing-sm);
    background-color: var(--cp-background-primary);
    box-shadow:
      var(--cp-drop-shadow-3xs-offset-x) var(--cp-drop-shadow-3xs-offset-y) var(--cp-drop-shadow-3xs-blur)
        fn.px-to-rem(-4) var(--cp-drop-shadow-3xs-color),
      0 0 0 var(--cp-dimensions-1) var(--cp-alert-shadow);
    gap: var(--cp-spacing-md);
  }

  &__icon {
    width: var(--cp-dimensions-4);
    height: var(--cp-dimensions-4);
    margin: var(--cp-spacing-sm-md) var(--cp-spacing-sm);
    color: var(--cp-alert-icon);
  }

  &__body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--cp-spacing-md);
  }

  &__content {
    display: flex;
    flex: 1;
    flex-direction: column;
    padding: var(--cp-spacing-sm) 0;
    gap: var(--cp-spacing-sm);
  }

  &__actions {
    display: flex;
    gap: var(--cp-spacing-md);
  }

  &__title {
    color: var(--cp-alert-title);
    font-size: var(--cp-text-size-sm);
    font-weight: 600;
    line-height: var(--cp-line-height-sm);
  }

  &__contentText {
    color: var(--cp-alert-text);
    font-size: var(--cp-text-size-sm);
    font-weight: 400;
    line-height: var(--cp-line-height-sm);
  }

  &--isInline {
    .cpAlert__body {
      flex-flow: row wrap;
      align-items: center;
      justify-content: space-between;
    }

    .cpAlert__content {
      flex: 0 1 auto;
    }
  }

  &--isNeutral {
    --cp-alert-border: var(--cp-border-soft);
    --cp-alert-shadow: var(--cp-utility-neutral-100);
    --cp-alert-icon: var(--cp-foreground-primary);
    --cp-alert-title: var(--cp-text-primary);
    --cp-alert-text: var(--cp-text-secondary);
  }

  &--isAccent {
    --cp-alert-border: var(--cp-border-accent-primary);
    --cp-alert-shadow: var(--cp-utility-accent-100);
    --cp-alert-icon: var(--cp-foreground-accent-secondary);
    --cp-alert-title: var(--cp-text-accent-primary);
    --cp-alert-text: var(--cp-text-accent-secondary);
  }

  &--isSuccess {
    --cp-alert-border: var(--cp-border-success-primary);
    --cp-alert-shadow: var(--cp-utility-success-100);
    --cp-alert-icon: var(--cp-foreground-success-secondary);
    --cp-alert-title: var(--cp-text-success-primary);
    --cp-alert-text: var(--cp-text-success-secondary);
  }

  &--isWarning {
    --cp-alert-border: var(--cp-border-warning-primary);
    --cp-alert-shadow: var(--cp-utility-warning-100);
    --cp-alert-icon: var(--cp-foreground-warning-secondary);
    --cp-alert-title: var(--cp-text-warning-primary);
    --cp-alert-text: var(--cp-text-warning-secondary);
  }

  &--isError {
    --cp-alert-border: var(--cp-border-error-primary);
    --cp-alert-shadow: var(--cp-utility-error-100);
    --cp-alert-icon: var(--cp-foreground-error-secondary);
    --cp-alert-title: var(--cp-text-error-primary);
    --cp-alert-text: var(--cp-text-error-secondary);
  }
}
</style>
