<template>
  <view 
    class="nana-notify-container"
    :style="{
      ...selectStyleType<ViewStyle, INotifyPosition>(position, 'center', {
        center: {
          justifyContent: 'center',
        },
        top: {
          justifyContent: 'flex-start',
          paddingTop: theme.resolveThemeSize('NotifyMarginWhenTop', 100),
        },
        bottom: {
          justifyContent: 'flex-end',
          paddingBottom: theme.resolveThemeSize('NotifyMarginWhenBottom', 100),
        },
      }),
      pointerEvents: 'none',
      ...themeStyles.notifyContainerStyle.value,
    }"
  >
    <view 
      v-for="item in items"
      :key="item.id"
      :class="[
        'nana-notify',
        item.showState ? 'show' : 'hide',
      ]"
      :style="{
        pointerEvents: 'auto',
        ...themeStyles.notifyStyle.value,
        ...selectStyleType(item.type, 'text', {
          text: {},
          loading: {},
          success: {
            backgroundColor: theme.resolveThemeColor('NotifySuccessBackgroundColor', 'background.success'),
          },
          fail: {
            backgroundColor: theme.resolveThemeColor('NotifyFailBackgroundColor', 'background.danger'),
          },
          info: {
            backgroundColor: theme.resolveThemeColor('NotifyInfoBackgroundColor', 'background.info'),
          },
          offline: {
            backgroundColor: theme.resolveThemeColor('NotifyOfflineBackgroundColor', 'background.warning'),
          },
        }),
        ...item.notifyStyle,
      }"
      @click="itemClick(item as NotifyItemData)"
    >
      <slot name="item" 
        :id="item.id"
        :item="item"
        :tag="item.tag"
      >
        <ActivityIndicator 
          v-if="item.type === 'loading'"
          :color="item.textStyle?.color as string || themeStyles.notifyTextStyle.value.color"
          :size="themeStyles.notifyIconStyle.value.size"
        />
        <Icon
          v-else-if="item.type !== 'text' || item.icon"
          :icon="item.icon ?? iconType[item.type!]"
          :color="item.textStyle?.color as string || themeStyles.notifyTextStyle.value.color"
          :size="themeStyles.notifyIconStyle.value.size"
          v-bind="item.iconProps"
        />
        <Height v-if="item.type !== 'text'" :size="themeStyles.notifyIconStyle.value.marginBottom" />
        <slot name="content">
          <text :style="{
            ...themeStyles.notifyTextStyle.value,
            ...item.textStyle
          }">
            {{ item.content }}
          </text>
        </slot>
        <Button 
          v-if="item.button"
          type="text"
          size="small"
          :text="item.button"
          v-bind="item.buttonProps"
          @click="item.onButtonClick"
        />
      </slot>
    </view>
  </view>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';
import { SimpleDelay, ArrayUtils } from '@imengyu/imengyu-utils';
import { useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
import { DynamicColor, DynamicSize, DynamicSize2, DynamicVar, selectStyleType } from '../theme/ThemeTools';
import type { IconProps } from '../basic/Icon.vue';
import ActivityIndicator from '../basic/ActivityIndicator.vue';
import Icon from '../basic/Icon.vue';
import Height from '../layout/space/Height.vue';
import type { ButtonProp } from '../basic/Button.vue';
import Button from '../basic/Button.vue';

export type INotifyPosition = 'top'|'bottom'|'center';
export type INotifyType = 'text'|'loading'|'success'|'fail'|'info'|'offline';

export interface NotifyProps {
  /**
   * 提示显示位置
   * @default 'top'
   */
  position?: INotifyPosition;
}
export interface NotifyShowProps {
  /**
   * 用于自定义渲染
   */
  id?: number,
  /**
   * 用于自定义渲染
   */
  tag?: string,
  /**
   * 自动关闭的延时，单位ms。为0不会自动关闭
   * @default 4000
   */
  duration?: number;
  /**
   * 图标类型
   */
  type?: INotifyType;
  /**
   * 自定义图标
   */
  icon?: string;
  /**
   * 内容
   */
  content?: string;
  /**
   * 按钮文字
   */
  button?: string;
  /**
   * 按钮属性
   */
  buttonProps?: ButtonProp;
  /**
   * 图标自定义属性
   */
  iconProps?: IconProps;
  /**
   * 是否在点击后关闭
   * @default false
   */
  closeOnClick?: boolean;
  /**
   * 提示容器的自定义样式
   */
  notifyStyle?: ViewStyle;
  /**
   * 提示文字的自定义样式
   */
  textStyle?: TextStyle;
  /**
   * 按钮点击回调
   */
  onButtonClick?: (e: any) => void;
  /**
   * 关闭后回调
   */
  onClose?: () => void;
  /**
   * 点击回调
   */
  onClick?: () => void;
}

const props = withDefaults(defineProps<NotifyProps>(), {
  position: 'top',
  forbidClick: false,
  closeOnClick: false,
})

const theme = useTheme();
const iconType: {
  [key: string]: string
} = {
  success: theme.getVar('NotifyIconSuccess', 'success'),
  fail: theme.getVar('NotifyIconError', 'error'),
  offline: theme.getVar('NotifyIconOffline', 'cry'),
  info: theme.getVar('NotifyIconInfo', 'prompt'),
};

const themeStyles = theme.useThemeStyles({
  notifyContainerStyle: {
    gap: DynamicSize('NotifyContainerGap', 15),
  },
  notifyStyle: {
    backgroundColor: DynamicColor('NotifyBackgroundColor', 'background.notify'),
    padding: DynamicSize2('NotifyPaddingVertical', 'NotifyPaddingHorizontal', 25, 30),
    borderRadius: DynamicSize('NotifyRadius', 16),
    boxShadow: '0 0 10px 0 rgba(0, 0, 0, 0.05)',
    gap: DynamicSize('NotifyGap', 21),
  },
  notifyTextStyle: {
    color: DynamicColor('NotifyTextColor', 'text.content'),
  },
  notifyIconStyle: {
    size: DynamicVar('NotifyIconSize', 45),
    marginBottom: DynamicSize('NotifyIconMarginBottom', 12),
  },
})

interface NotifyItemData extends NotifyShowProps {
  id: number;
  showState: boolean;
  showTimer: SimpleDelay,
  hideTimer: SimpleDelay,
  updateProps(options: NotifyShowProps): void;
  close() : void;
}

const items = ref<NotifyItemData[]>([]);
let ids = 0;

function show(options: NotifyShowProps) {
  const { 
    duration = 4000,
    type = 'text',
  } = options;

  const item = reactive<NotifyItemData>({
    ...options,
    id: options.id ?? ids++,
    duration,
    type,
    updateProps(options: NotifyShowProps) {
      for (const key in options) {
        const v = (options as any)[key];
        if (v !== undefined)
          (this as any)[key] = v;
      }
    },
    close() {
      this.showState = false;
      this.hideTimer.start();
      this.onClose?.();
    },
    showState: false,
    showTimer: new SimpleDelay(undefined, () => {
      item.close()
    }, duration),
    hideTimer: new SimpleDelay(undefined, () => {
      ArrayUtils.remove(items.value, item);
    }, 300),
  });

  if (duration > 0)
    item.showTimer.start();

  items.value.push(item);
  setTimeout(() => item.showState = true, 20);

  return item;
}
function itemClick(item: NotifyItemData) {
  item.onClick?.();
  if (props.closeOnClick)
    item.close();
}
function closeAll() {
  ArrayUtils.clear(items.value);
}

export interface NotifyItemInstance {
  updateProps(options?: Omit<NotifyShowProps, 'duration'|'onClose'>): void;
  close() : void;
}
export interface NotifyInstance {
  show(options: NotifyShowProps) : NotifyItemInstance;
  closeAll(): void;
}

defineExpose<NotifyInstance>({
  show,
  closeAll,
})

</script>

<style lang="scss">
.nana-notify-container {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 100;
  

  .nana-notify {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity ease-in-out 0.3s;

    &.show {
      opacity: 1;
    }
  }
}

</style>