<script setup lang="ts" generic="T extends Record<string, any>">
import { computed, inject, ref, useTemplateRef } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { message } from 'ant-design-vue';

import ConfirmModal from '@/components/ConfirmModal.vue';
import SvgIcon from '@/components/SvgIcon.vue';
import { t } from '@/i18n';
import { addUnit } from '@/utils';
import { CLOSE_MODAL_GUIDANCE, FINISH_MODAL_GUIDANCE, IS_USED_IN_MODAL_GUIDANCE } from '@/constants/inject-key';

import type { CSSProperties } from 'vue';
import type { FormInstance } from 'ant-design-vue';
import type { FormRules, UseGuideStepItem, UseGuideStepItemInstance } from '@/types';

interface Props {
  title: string;
  steps: UseGuideStepItem[];
  form: T;
  rules: FormRules<T>;
  contentOffset?: number;
  headerMargin?: number;
}

const props = defineProps<Props>();

const isUsedInModalGuidance = inject(IS_USED_IN_MODAL_GUIDANCE, false);
const closeModalGuidance = inject(CLOSE_MODAL_GUIDANCE, undefined);
const finishModalGuidance = inject(FINISH_MODAL_GUIDANCE, undefined);
const route = useRoute();
const router = useRouter();
const current = ref(0);

const currentStep = computed(() => {
  return props.steps[current.value];
});

const isFirstStep = computed(() => {
  return current.value === 0;
});

const contentStyle = computed<CSSProperties>(() => {
  // const contentOffset = props.steps[current.value].contentOffset ?? props.contentOffset;

  return {
    // paddingLeft: addUnit(contentOffset ?? 312),
  };
});

const headerStyle = computed<CSSProperties>(() => {
  const dividerWidth = currentStep.value.hideHeaderDivider ? 0 : 1;
  const headerMargin = currentStep.value.headerMargin ?? props.headerMargin;
  const defaultMargin = isUsedInModalGuidance ? 24 : 40;

  return {
    borderBottomWidth: addUnit(dividerWidth),
    marginBottom: addUnit(headerMargin ?? defaultMargin),
  };
});

const goToStep = (index: number) => {
  current.value = index;
};

const goNextStep = () => {
  current.value++;
};

const goPrevStep = async () => {
  if (isFirstStep.value) {
    goOutOfUseGuide();
    return;
  }

  const hasGoBack = await stepRef.value?.goBack?.();

  if (!hasGoBack) {
    current.value--;
  }
};

const goOutOfUseGuide = () => {
  if (isUsedInModalGuidance) {
    confirmModalRef.value?.hideView();
    closeModalGuidance?.();
    return;
  }

  // 配置完成某一项时，路由查询参数 doneItems 会携带该项的页面路径，据此判断是否已经配置该项
  let doneItems = route.query.doneItems ?? '';

  if (currentStep.value.isLastStep) {
    doneItems += route.path;
  }

  const donePaths = [...new Set((doneItems as string).split('/'))];

  router.replace({
    path: '/first-usage',
    query: {
      doneItems: donePaths.join('/'),
    },
  });
};

const confirmModalRef = useTemplateRef('confirmModal');

const confirmModalDescription = computed(() => {
  const endText = isUsedInModalGuidance ? t('common.andCloseModal') : t('common.returnFirstUse');
  return t('common.skipStepConfirm', { name: currentStep.value.title }) + endText;
});

const skipCurrentStep = () => {
  confirmModalRef.value?.showView();
};

const formRef = ref<FormInstance>();
const stepRef = useTemplateRef<UseGuideStepItemInstance>('stepItem');

const exportStepContent = async () => {
  await stepRef.value?.exportData?.();
};

const finishCurrentStep = async () => {
  try {
    await formRef.value?.validate();
    await stepRef.value?.finish?.();

    if (currentStep.value.isLastStep) {
      goOutOfUseGuide();
      finishModalGuidance?.();
    } else {
      goNextStep();
    }
  } catch (err) {
    if (err instanceof Error) {
      message.error(err.message);
    }

    console.error(err);
  }
};
</script>

<template>
  <ALayout class="use-guide-container">
    <ALayoutSider v-if="!isUsedInModalGuidance" class="use-guide-sider" :width="268">
      <div class="use-guide-title">{{ title }}</div>
      <div class="use-guide-steps">
        <ASteps :current="current" :items="steps" direction="vertical" />
      </div>
      <AButton class="icon-button doc-button">
        <SvgIcon name="eye-o" />
        {{ $t('common.viewDoc') }}
      </AButton>
    </ALayoutSider>
    <ALayout>
      <ALayoutContent class="use-guide-main" :style="contentStyle">
        <div v-show="!currentStep.hideHeader" class="step-header" :style="headerStyle">
          <div class="step-title">{{ currentStep.stepTitle || currentStep.title }}</div>
          <div v-if="!isUsedInModalGuidance" class="step-description">{{ currentStep.stepDescription }}</div>
        </div>
        <AForm
          ref="formRef"
          :model="form"
          :rules="rules"
          :layout="currentStep.formLayout"
          :label-align="currentStep.labelAlign"
          :label-col="currentStep.labelCol"
          :wrapper-col="currentStep.wrapperCol"
          :colon="false"
        >
          <component
            ref="stepItem"
            :is="currentStep.component"
            :form="form"
            :steps="steps"
            :step-index="current"
            :go-to-step="goToStep"
          />
        </AForm>
      </ALayoutContent>
      <ALayoutFooter class="use-guide-footer">
        <div class="use-guide-step-button-container">
          <div>
            <AButton
              :type="isUsedInModalGuidance ? 'default' : 'text'"
              :disabled="currentStep.isLastStep"
              @click="skipCurrentStep"
            >
              {{ $t('common.skip') }}
            </AButton>
            <AButton
              v-show="(!isUsedInModalGuidance || !isFirstStep) && !currentStep.prevStepButtonHide"
              :type="isUsedInModalGuidance ? 'default' : 'text'"
              @click="goPrevStep"
            >
              {{ isUsedInModalGuidance ? $t('common.prevStep') : $t('common.return') }}
            </AButton>
          </div>
          <div>
            <AButton v-if="currentStep.exportButtonShow" class="icon-button export-button" @click="exportStepContent">
              <SvgIcon name="download" />
              {{ $t('common.exportToLocal') }}
            </AButton>
            <AButton
              v-show="!currentStep.nextStepButtonHide"
              class="next-step-button"
              type="primary"
              :disabled="currentStep.nextStepButtonDisabled"
              @click="finishCurrentStep"
            >
              {{ currentStep.nextStepButtonText || t('common.nextStep') }}
            </AButton>
          </div>
          <ConfirmModal
            ref="confirmModal"
            :title="$t('common.skipConfirm')"
            :description-text="confirmModalDescription"
            :icon="{ name: 'exclamation' }"
            icon-bg-color="#F56C6C"
            @confirm="goOutOfUseGuide"
          />
        </div>
      </ALayoutFooter>
    </ALayout>
  </ALayout>
</template>

<style lang="scss" scoped>
.use-guide-container {
  height: 100%;
}

.use-guide-sider {
  padding-top: 48px;
  padding-bottom: 40px;
  background: #f0f0f0;

  :deep(.ant-layout-sider-children) {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .use-guide-title {
    margin-bottom: 32px;
    text-align: center;
  }

  .use-guide-steps {
    flex: 1;
  }

  :deep(.ant-steps) {
    .ant-steps-item {
      height: 80px;
    }

    .ant-steps-item-wait {
      .ant-steps-item-icon {
        background-color: initial;
        border-color: var(--antd-color-fill);
      }

      .ant-steps-icon {
        color: var(--antd-color-text-quaternary);
      }
    }

    .ant-steps-item-process {
      .ant-steps-item-title {
        font-weight: 500;
      }
    }

    .ant-steps-item-finish {
      .ant-steps-item-icon {
        background-color: initial;
        border-color: var(--antd-color-primary);
      }

      .ant-steps-item-title {
        color: var(--antd-color-text-secondary);
      }
    }

    .ant-steps-item-process,
    .ant-steps-item-wait {
      .ant-steps-item-tail::after {
        background-color: var(--antd-color-fill);
      }
    }
  }

  .doc-button {
    width: 120px;
    height: 40px;
  }
}

.use-guide-main {
  padding: 40px;
  padding-bottom: 0;
  overflow: auto;
  background: var(--antd-color-bg-base);

  .step-header {
    padding-bottom: 40px;
    border-bottom: 1px solid #e4e7ed;
  }

  .step-title {
    margin-bottom: 8px;
    font-size: 20px;
    font-weight: 500;
    line-height: 28px;
    color: var(--antd-color-text);
  }

  .step-description {
    min-height: 22px;
    font-size: 14px;
    line-height: 22px;
    color: var(--antd-color-text-secondary);
  }
}

.use-guide-footer {
  padding-inline: 40px;
  background: var(--antd-color-bg-base);
}

.use-guide-step-button-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 100%;

  button {
    height: 40px;
  }

  .ant-btn-text {
    width: 80px;
  }

  .export-button {
    width: 136px;
    margin-right: 16px;
  }

  .next-step-button {
    width: 128px;
    font-size: 16px;
  }
}

.modal-guidance-modal {
  .use-guide-main {
    padding: 0;
    overflow-x: hidden;
  }

  .step-header {
    padding-bottom: 0;
    margin-top: 16px;
    border: none;
  }

  .step-title {
    padding-left: 8px;
    margin-bottom: 0;
    font-size: 16px;
    font-weight: 600;
    line-height: 24px;
    color: #333;
    border-left: 2px solid var(--antd-color-primary);
  }

  .use-guide-footer {
    padding-inline: 0;
    padding-bottom: 4px;
  }

  .use-guide-step-button-container {
    justify-content: flex-end;

    button {
      min-width: 76px;
      height: 32px;
      margin-left: 16px;
      font-size: 14px;
    }

    .next-step-button {
      width: auto;
      font-size: 14px;
    }
  }
}
</style>
