<script setup lang="ts">
import { computed, nextTick, reactive, ref, watch } from 'vue';
import { useResizeObserver } from '@vueuse/core';
import dayjs from 'dayjs';
import { RDMS_TASK_ITEM_TYPE_DICT_CODE } from '@/constants/dict';
import { fetchCreatePersonalItem, fetchGetPersonalItemDetail, fetchUpdatePersonalItem } from '@/service/api';
import { useAuthStore } from '@/store/modules/auth';
import { useForm, useFormRules } from '@/hooks/common/form';
import BusinessAttachmentUploader from '@/components/custom/business-attachment-uploader.vue';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
import BusinessFormSection from '@/components/custom/business-form-section.vue';
import BusinessRichTextEditor from '@/components/custom/business-rich-text-editor.vue';
import DictSelect from '@/components/custom/dict-select.vue';
import { isEmptyRichText } from './personal-item-shared';

defineOptions({ name: 'PersonalItemOperateDialog' });

type PersonalItemOperateType = UI.TableOperateType | 'view';

interface Props {
  operateType: PersonalItemOperateType;
  rowData?: Api.PersonalItem.PersonalItem | null;
}

const props = defineProps<Props>();

const emit = defineEmits<{
  submitted: [];
}>();

const visible = defineModel<boolean>('visible', {
  default: false
});

const authStore = useAuthStore();
const currentUserId = computed(() => authStore.userInfo.userId || 'current-user');

const { formRef, validate } = useForm();
const { createRequiredRule } = useFormRules();

const attachmentUploaderRef = ref<InstanceType<typeof BusinessAttachmentUploader> | null>(null);
const richTextEditorRef = ref<InstanceType<typeof BusinessRichTextEditor> | null>(null);
const leftColRef = ref<HTMLElement>();
const editorHeight = ref<string>('45vh');

const ATTACHMENT_SECTION_RESERVE_PX = 140;

useResizeObserver(leftColRef, entries => {
  const h = entries[0]?.contentRect.height;
  if (h && h > 120) {
    editorHeight.value = `${Math.max(h - 60 - ATTACHMENT_SECTION_RESERVE_PX, 200)}px`;
  }
});

const isEdit = computed(() => props.operateType === 'edit');
const isView = computed(() => props.operateType === 'view');
const detailLoading = ref(false);
const submitting = ref(false);

interface Model {
  taskTitle: string;
  type: string;
  plannedStartDate: string | null;
  plannedEndDate: string | null;
  taskDesc: string | null;
  attachments: Api.Project.AttachmentItem[];
}

const model = reactive<Model>(createDefaultModel());

const title = computed(() => {
  if (isView.value) {
    return '个人事项详情';
  }

  return isEdit.value ? '编辑个人事项' : '新增个人事项';
});

function createDefaultModel(): Model {
  return {
    taskTitle: '',
    type: '',
    plannedStartDate: null,
    plannedEndDate: null,
    taskDesc: null,
    attachments: []
  };
}

function isPlannedDateRangeValid(startDate: string | null, endDate: string | null) {
  if (!startDate || !endDate) {
    return true;
  }

  return !dayjs(endDate).isBefore(dayjs(startDate), 'day');
}

const rules = computed(
  () =>
    ({
      taskTitle: [
        createRequiredRule('请输入事项标题'),
        {
          validator: (_rule, value: string, callback) => {
            if (!value?.trim()) {
              callback(new Error('请输入事项标题'));
              return;
            }

            callback();
          },
          trigger: 'blur'
        }
      ],
      type: [createRequiredRule('请选择事项类型')],
      plannedStartDate: [createRequiredRule('请选择计划开始日期')],
      plannedEndDate: [
        createRequiredRule('请选择计划结束日期'),
        {
          validator: (_rule, value: string | null, callback) => {
            if (!isPlannedDateRangeValid(model.plannedStartDate, value)) {
              callback(new Error('计划结束日期不能早于计划开始日期'));
              return;
            }

            callback();
          },
          trigger: 'change'
        }
      ]
    }) satisfies Record<string, App.Global.FormRule[]>
);

async function initModel() {
  detailLoading.value = true;

  Object.assign(model, createDefaultModel());

  if ((isEdit.value || isView.value) && props.rowData) {
    const { error, data } = await fetchGetPersonalItemDetail(props.rowData.id);

    if (!error && data) {
      model.taskTitle = data.taskTitle;
      model.type = data.type;
      model.plannedStartDate = data.plannedStartDate;
      model.plannedEndDate = data.plannedEndDate;
      model.taskDesc = data.taskDesc;
      model.attachments = data.attachments ? [...data.attachments] : [];
    }
  }

  detailLoading.value = false;

  await nextTick();
  attachmentUploaderRef.value?.initSession();
  richTextEditorRef.value?.initSession();
  formRef.value?.clearValidate();
}

async function handleSubmit() {
  if (isView.value) {
    visible.value = false;
    return;
  }

  await validate();

  if (attachmentUploaderRef.value?.hasUploading) {
    window.$message?.warning('附件正在上传中，请稍候');
    return;
  }

  const payload: Api.PersonalItem.SavePersonalItemParams = {
    taskTitle: model.taskTitle.trim(),
    type: model.type,
    ownerId: currentUserId.value,
    plannedStartDate: model.plannedStartDate,
    plannedEndDate: model.plannedEndDate,
    taskDesc: isEmptyRichText(model.taskDesc) ? null : (model.taskDesc ?? null),
    attachments: [...model.attachments]
  };

  submitting.value = true;

  const result =
    isEdit.value && props.rowData
      ? await fetchUpdatePersonalItem({ id: props.rowData.id, ...payload })
      : await fetchCreatePersonalItem(payload);

  submitting.value = false;

  if (result.error) {
    return;
  }

  await Promise.all([attachmentUploaderRef.value?.commit(), richTextEditorRef.value?.commit()]);

  window.$message?.success(isEdit.value ? '个人事项修改成功' : '个人事项创建成功');
  visible.value = false;
  emit('submitted');
}

watch(
  () => visible.value,
  value => {
    if (value) {
      initModel();
    }
  }
);
</script>

<template>
  <BusinessFormDialog
    v-model="visible"
    :title="title"
    width="1100px"
    :loading="detailLoading"
    :confirm-loading="submitting"
    :show-footer="!isView"
    max-body-height="78vh"
    @confirm="handleSubmit"
  >
    <ElForm
      ref="formRef"
      :model="model"
      :rules="rules"
      label-position="top"
      :validate-on-rule-change="false"
      class="personal-item-operate-dialog__form"
    >
      <div class="personal-item-operate-dialog__grid">
        <div ref="leftColRef" class="personal-item-operate-dialog__col-left">
          <BusinessFormSection title="事项信息">
            <ElFormItem label="事项标题" prop="taskTitle">
              <ElInput
                v-model="model.taskTitle"
                :clearable="!isView"
                :disabled="isView"
                maxlength="300"
                placeholder="请输入事项标题"
              />
            </ElFormItem>

            <ElFormItem label="事项类型" prop="type">
              <DictSelect
                v-model="model.type"
                :dict-code="RDMS_TASK_ITEM_TYPE_DICT_CODE"
                :clearable="!isView"
                :disabled="isView"
                placeholder="请选择事项类型"
              />
            </ElFormItem>

            <ElFormItem label="计划开始日期" prop="plannedStartDate">
              <ElDatePicker
                v-model="model.plannedStartDate"
                :disabled="isView"
                type="date"
                value-format="YYYY-MM-DD"
                placeholder="请选择计划开始日期"
                class="personal-item-operate-dialog__date-picker"
              />
            </ElFormItem>

            <ElFormItem label="计划结束日期" prop="plannedEndDate">
              <ElDatePicker
                v-model="model.plannedEndDate"
                :disabled="isView"
                type="date"
                value-format="YYYY-MM-DD"
                placeholder="请选择计划结束日期"
                class="personal-item-operate-dialog__date-picker"
              />
            </ElFormItem>
          </BusinessFormSection>
        </div>

        <div class="personal-item-operate-dialog__col-right">
          <BusinessFormSection title="事项说明">
            <ElFormItem class="personal-item-operate-dialog__desc-item" prop="taskDesc">
              <BusinessRichTextEditor
                ref="richTextEditorRef"
                v-model="model.taskDesc"
                :height="editorHeight"
                :disabled="isView"
                upload-directory="personal-item"
                placeholder="请输入事项说明"
              />
            </ElFormItem>
          </BusinessFormSection>

          <BusinessFormSection title="附件">
            <ElFormItem class="personal-item-operate-dialog__attachment-item">
              <BusinessAttachmentUploader
                ref="attachmentUploaderRef"
                v-model="model.attachments"
                directory="personal-item"
                :disabled="isView"
              />
            </ElFormItem>
          </BusinessFormSection>
        </div>
      </div>
    </ElForm>
  </BusinessFormDialog>
</template>

<style scoped>
.personal-item-operate-dialog__grid {
  display: grid;
  grid-template-columns: 360px 1fr;
  gap: 24px;
  align-items: start;
}

.personal-item-operate-dialog__col-left,
.personal-item-operate-dialog__col-right {
  min-width: 0;
}

.personal-item-operate-dialog__col-right {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.personal-item-operate-dialog__desc-item,
.personal-item-operate-dialog__attachment-item {
  margin-bottom: 0;
}

@media (width <= 1024px) {
  .personal-item-operate-dialog__grid {
    grid-template-columns: 1fr;
  }
}

:deep(.personal-item-operate-dialog__date-picker.el-date-editor.el-input) {
  width: 100%;
}
</style>
