<template>
  <toast class="cpToasts" @mouse-enter="handleMouse" @mouse-leave="handleMouse">
    <template #container="{ message, closeCallback }">
      <div class="cpToast" :class="getDynamicClass(message.severity)">
        <div class="cpToast__inner">
          <cp-icon class="cpToast__icon" size="16" :type="getDynamicIcon(message.severity)" />
          <div class="cpToast__content">
            <span class="cpToast__summary">{{ message.summary }}</span>
            <span v-if="message.detail" class="cpToast__detail">{{ message.detail }}</span>
          </div>
          <button class="cpToast__close" type="button" @click="closeCallback">
            <cp-icon class="cpToast__icon cpToast__icon--isClose" size="16" type="x" />
          </button>
        </div>
        <div v-if="hasActions(message)" class="cpToast__actions">
          <cp-button
            v-if="message.primaryAction"
            appearance="primary"
            class="cpToast__action"
            :color="getButtonColor(message.severity)"
            is-square
            size="sm"
            @click="handleActionClick(message.primaryAction.onClick, closeCallback)"
          >
            <template v-if="message.primaryAction.leadingIcon" #leading-icon>
              <cp-icon :type="message.primaryAction.leadingIcon" />
            </template>
            {{ message.primaryAction.label }}
            <template v-if="message.primaryAction.trailingIcon" #trailing-icon>
              <cp-icon :type="message.primaryAction.trailingIcon" />
            </template>
          </cp-button>
          <cp-button
            v-if="message.secondaryAction"
            appearance="minimal"
            class="cpToast__action"
            :color="getButtonColor(message.severity)"
            is-square
            size="sm"
            @click="handleActionClick(message.secondaryAction.onClick, closeCallback)"
          >
            <template v-if="message.secondaryAction.leadingIcon" #leading-icon>
              <cp-icon :type="message.secondaryAction.leadingIcon" />
            </template>
            {{ message.secondaryAction.label }}
            <template v-if="message.secondaryAction.trailingIcon" #trailing-icon>
              <cp-icon :type="message.secondaryAction.trailingIcon" />
            </template>
          </cp-button>
        </div>
        <div
          v-if="displayTimer(message)"
          aria-hidden="true"
          class="cpToast__timer"
          role="presentation"
          :style="getTimerBarStyle(message.life)"
        />
      </div>
    </template>
  </toast>
</template>

<script setup lang="ts">
import Toast from 'primevue/toast'

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

interface Message {
  detail?: string
  life?: number
  primaryAction?: {
    label: string
    leadingIcon?: string
    onClick: VoidFunction
    trailingIcon?: string
  }
  secondaryAction?: {
    label: string
    leadingIcon?: string
    onClick: VoidFunction
    trailingIcon?: string
  }
  severity: CpToastTypes
  showTimer?: boolean
  summary: string
}

const displayTimer = (message: Message) => message.showTimer && message.life !== undefined

const getDynamicClass = (severity: string) => `cpToast--is${capitalizeFirstLetter(severity)}`

const getDynamicIcon = (severity: CpToastTypes) => {
  switch (severity) {
    case CpToastTypes.ERROR:
      return 'alert-octagon'
    case CpToastTypes.INFO:
      return 'info'
    case CpToastTypes.SUCCESS:
      return 'check-circle'
    case CpToastTypes.WARNING:
      return 'alert-triangle'
    default:
      return 'intent'
  }
}

const getButtonColor = (severity: string) => {
  switch (severity) {
    case CpToastTypes.ERROR:
      return 'red'
    case CpToastTypes.SUCCESS:
      return 'green'
    case CpToastTypes.WARNING:
      return 'orange'
    default:
      return 'purple'
  }
}

const hasActions = (message: Message) => !!message.primaryAction || !!message.secondaryAction

const getTimerBarStyle = (life: number) => ({ animationDuration: `${life}ms` })

const handleActionClick = (onClick: VoidFunction, closeCallback: VoidFunction) => {
  onClick()
  closeCallback()
}

const handleMouse = () => true
</script>

<style lang="scss">
.p-toast-message-move,
.p-toast-message-enter-active {
  transition:
    transform 400ms var(--cp-easing-elastic),
    opacity 200ms var(--cp-easing-elastic);
}

.p-toast-message-move,
.p-toast-message-leave-active {
  transition:
    transform 400ms ease,
    opacity 200ms ease;
}

.p-toast-message-enter-from,
.p-toast-message-leave-to {
  z-index: -1;
  opacity: 0;
  transform: translate3d(0, calc(var(--cp-dimensions-1) * -7.5), 0) scale3d(0.75, 0.75, 1);
}

.cpToasts {
  pointer-events: none;
}

.cpToasts .p-toast-message-leave-active:not(:only-child) {
  position: absolute;
  right: 0;
  left: 0;
}

.cpToasts[data-p$='center'] {
  transform: translate3d(-50%, 0, 0);
}

.cpToasts[data-p^='bottom'] {
  .p-toast-message-enter-from,
  .p-toast-message-leave-to {
    transform: translate3d(0, calc(var(--cp-dimensions-1) * 7.5), 0) scale3d(0.75, 0.75, 1);
  }
}

.cpToasts > div {
  display: flex;
  flex-direction: column;
  gap: var(--cp-spacing-md);
  pointer-events: auto;
}

.cpToast {
  --toaster-shadow: #{var(--cp-drop-shadow-md-offset-x)} #{var(--cp-drop-shadow-md-offset-y)}
    #{var(--cp-drop-shadow-md-blur)} #{var(--cp-drop-shadow-md-spread)} #{var(--cp-drop-shadow-md-color)};

  position: relative;
  display: inline-flex;
  overflow: hidden;
  max-width: calc(var(--cp-dimensions-1) * 100);
  flex-direction: column;
  padding: var(--cp-spacing-lg);
  border-radius: var(--cp-radius-md);
  background-color: var(--cp-background-primary);
  box-shadow: var(--toaster-shadow);
  gap: var(--cp-spacing-md);

  &__inner {
    display: flex;
    align-items: flex-start;
    gap: var(--cp-spacing-md);
  }

  &__content {
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--cp-spacing-sm);
    text-align: left;
  }

  &__icon {
    color: var(--cp-text-accent-primary);

    &:not(.cpToast__icon--isClose) {
      padding-top: var(--cp-spacing-xs);
    }
  }

  &__summary,
  &__detail {
    font-size: var(--cp-text-size-sm);
    line-height: var(--cp-line-height-sm);
  }

  &__summary {
    color: var(--cp-text-accent-primary);
    font-weight: 600;

    &::first-letter {
      text-transform: capitalize;
    }
  }

  &__detail {
    color: var(--cp-text-accent-secondary);
    font-weight: 500;
  }

  &__actions {
    display: flex;
    justify-content: flex-end;
    margin-top: var(--cp-spacing-sm);
    gap: var(--cp-spacing-md);
  }

  &__close {
    display: flex;
    border-radius: var(--cp-radius-full);
    margin-top: var(--cp-spacing-xs);

    &:focus-visible {
      outline: var(--cp-dimensions-0_5) solid var(--cp-border-accent-solid);
    }
  }

  @keyframes toast-timer {
    from {
      transform: scale3d(1, 1, 1);
    }

    to {
      transform: scale3d(0, 1, 1);
    }
  }

  &__timer {
    position: absolute;
    top: auto;
    height: var(--cp-dimensions-1);
    animation-fill-mode: forwards;
    animation-name: toast-timer;
    animation-timing-function: linear;
    background-color: var(--cp-border-accent-solid);
    // stylelint-disable-next-line declaration-block-no-shorthand-property-overrides
    inset: 0;
    transform-origin: left;
  }

  &--isInfo {
    background-color: var(--cp-background-blue-primary);

    .cpToast__icon,
    .cpToast__summary {
      color: var(--cp-text-blue-primary);
    }

    .cpToast__detail {
      color: var(--cp-text-blue-secondary);
    }

    .cpToast__close {
      outline-color: var(--cp-border-blue-solid);
    }

    .cpToast__timer {
      background-color: var(--cp-border-blue-solid);
    }
  }

  &--isSuccess {
    background-color: var(--cp-background-success-primary);

    .cpToast__icon,
    .cpToast__summary {
      color: var(--cp-text-success-primary);
    }

    .cpToast__detail {
      color: var(--cp-text-success-secondary);
    }

    .cpToast__close {
      outline-color: var(--cp-border-success-solid);
    }

    .cpToast__timer {
      background-color: var(--cp-border-success-solid);
    }
  }

  &--isError {
    background-color: var(--cp-background-error-primary);

    .cpToast__icon,
    .cpToast__summary {
      color: var(--cp-text-error-primary);
    }

    .cpToast__detail {
      color: var(--cp-text-error-secondary);
    }

    .cpToast__close {
      outline-color: var(--cp-border-error-solid);
    }

    .cpToast__timer {
      background-color: var(--cp-border-error-solid);
    }
  }

  &--isWarning {
    background-color: var(--cp-background-warning-primary);

    .cpToast__icon,
    .cpToast__summary {
      color: var(--cp-text-warning-primary);
    }

    .cpToast__detail {
      color: var(--cp-text-warning-secondary);
    }

    .cpToast__close {
      outline-color: var(--cp-border-warning-solid);
    }

    .cpToast__timer {
      background-color: var(--cp-border-warning-solid);
    }
  }

  &:has(.cpToast__timer):hover .cpToast__timer {
    animation-play-state: paused;
  }
}

@media (max-width: 551px) {
  .cpToasts {
    right: 0 !important;
    left: 0;
    width: 100%;
    max-width: calc(100% - #{calc(var(--cp-spacing-2xl) * 3)});
    margin: 0 auto;
    text-align: center;
  }

  .cpToast {
    min-width: 100%;
    max-width: 100%;
  }
}

@media (max-width: 451px) {
  .cpToasts {
    max-width: calc(100% - #{var(--cp-spacing-2xl)});
  }
}
</style>
