<script setup lang="ts">
import { computed, nextTick, reactive, ref, watch } from 'vue';
import { RDMS_OVERTIME_DURATION_DICT_CODE } from '@/constants/dict';
import {
  fetchCreateOvertimeApplication,
  fetchGetLoginUserDirectManager,
  fetchGetOvertimeApplicationDetail,
  fetchUpdateRejectedOvertimeApplication
} from '@/service/api';
import { useAuthStore } from '@/store/modules/auth';
import { useForm, useFormRules } from '@/hooks/common/form';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
import BusinessFormSection from '@/components/custom/business-form-section.vue';
import DictSelect from '@/components/custom/dict-select.vue';

defineOptions({ name: 'OvertimeApplicationOperateDialog' });

type OperateType = 'add' | 'edit';

interface Props {
  operateType: OperateType;
  rowData?: Api.OvertimeApplication.OvertimeApplication | null;
}

const props = defineProps<Props>();

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

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

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

const detailLoading = ref(false);
const submitting = ref(false);
const approverName = ref('');

const currentUserName = computed(() => authStore.userInfo.nickname || authStore.userInfo.userName || '--');
const isEdit = computed(() => props.operateType === 'edit');
const title = computed(() => (isEdit.value ? '修改并重新提交' : '新增加班申请'));

const model = reactive<Api.OvertimeApplication.SaveOvertimeApplicationParams>(createDefaultModel());

const rules = computed(
  () =>
    ({
      overtimeDate: [createRequiredRule('请选择加班日期')],
      overtimeDuration: [createRequiredRule('请选择加班时长')],
      overtimeReason: [
        createRequiredRule('请输入加班原因'),
        {
          validator: (_rule, value: string, callback) => {
            if (!value?.trim()) {
              callback(new Error('请输入加班原因'));
              return;
            }

            callback();
          },
          trigger: 'blur'
        }
      ],
      overtimeContent: [
        createRequiredRule('请输入加班内容'),
        {
          validator: (_rule, value: string, callback) => {
            if (!value?.trim()) {
              callback(new Error('请输入加班内容'));
              return;
            }

            callback();
          },
          trigger: 'blur'
        }
      ],
      approverId: [createRequiredRule('请选择审核人')]
    }) satisfies Record<keyof Api.OvertimeApplication.SaveOvertimeApplicationParams, App.Global.FormRule[]>
);

function createDefaultModel(): Api.OvertimeApplication.SaveOvertimeApplicationParams {
  return {
    overtimeDate: '',
    overtimeDuration: '',
    overtimeReason: '',
    overtimeContent: '',
    approverId: ''
  };
}

async function loadDirectManagerAsDefaultApprover() {
  const { error, data } = await fetchGetLoginUserDirectManager();

  if (!error && data?.id) {
    model.approverId = data.id;
    approverName.value = data.nickname;
  }
}

async function initModel() {
  detailLoading.value = true;
  Object.assign(model, createDefaultModel());
  approverName.value = '';

  if (isEdit.value && props.rowData) {
    const { error, data } = await fetchGetOvertimeApplicationDetail(props.rowData.id);
    const detail = error || !data ? props.rowData : data;

    model.overtimeDate = detail.overtimeDate;
    model.overtimeDuration = detail.overtimeDuration;
    model.overtimeReason = detail.overtimeReason;
    model.overtimeContent = detail.overtimeContent;
    model.approverId = detail.approverId;
    approverName.value = detail.approverName;
  } else {
    await loadDirectManagerAsDefaultApprover();
  }

  detailLoading.value = false;

  await nextTick();
  formRef.value?.clearValidate();
}

async function handleSubmit() {
  await validate();

  const payload: Api.OvertimeApplication.SaveOvertimeApplicationParams = {
    overtimeDate: model.overtimeDate,
    overtimeDuration: model.overtimeDuration,
    overtimeReason: model.overtimeReason.trim(),
    overtimeContent: model.overtimeContent.trim(),
    approverId: model.approverId
  };

  submitting.value = true;

  const result =
    isEdit.value && props.rowData
      ? await fetchUpdateRejectedOvertimeApplication(props.rowData.id, payload)
      : await fetchCreateOvertimeApplication(payload);

  submitting.value = false;

  if (result.error) {
    return;
  }

  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"
    preset="md"
    :loading="detailLoading"
    :confirm-loading="submitting"
    @confirm="handleSubmit"
  >
    <ElForm ref="formRef" :model="model" :rules="rules" label-position="top" :validate-on-rule-change="false">
      <BusinessFormSection title="申请信息">
        <ElRow :gutter="16">
          <ElCol :span="12">
            <ElFormItem label="申请人">
              <ElInput
                class="overtime-application-operate-dialog__readonly-input"
                :model-value="currentUserName"
                readonly
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="审核人" prop="approverId">
              <ElInput
                class="overtime-application-operate-dialog__readonly-input"
                :model-value="approverName"
                readonly
                placeholder="暂无直属上级"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="加班日期" prop="overtimeDate" style="width: 100%">
              <ElDatePicker
                v-model="model.overtimeDate"
                class="w-full"
                type="date"
                value-format="YYYY-MM-DD"
                style="width: 100%"
                placeholder="请选择加班日期"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="加班时长" prop="overtimeDuration">
              <DictSelect
                v-model="model.overtimeDuration"
                :dict-code="RDMS_OVERTIME_DURATION_DICT_CODE"
                placeholder="请选择加班时长"
              />
            </ElFormItem>
          </ElCol>
        </ElRow>
      </BusinessFormSection>

      <BusinessFormSection title="加班说明">
        <ElRow :gutter="16">
          <ElCol :span="24">
            <ElFormItem label="加班原因" prop="overtimeReason">
              <ElInput
                v-model="model.overtimeReason"
                type="textarea"
                :rows="3"
                maxlength="500"
                show-word-limit
                placeholder="请输入加班原因"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="24">
            <ElFormItem label="加班内容" prop="overtimeContent">
              <ElInput
                v-model="model.overtimeContent"
                type="textarea"
                :rows="4"
                maxlength="1000"
                show-word-limit
                placeholder="请输入加班内容"
              />
            </ElFormItem>
          </ElCol>
        </ElRow>
      </BusinessFormSection>
    </ElForm>
  </BusinessFormDialog>
</template>

<style scoped>
:deep(.overtime-application-operate-dialog__readonly-input .el-input__wrapper) {
  background: linear-gradient(180deg, rgb(241 245 249 / 98%), rgb(226 232 240 / 94%)), rgb(241 245 249);
  box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
  cursor: default;
}

:deep(.overtime-application-operate-dialog__readonly-input .el-input__wrapper:hover),
:deep(.overtime-application-operate-dialog__readonly-input.is-focus .el-input__wrapper) {
  box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
}

:deep(.overtime-application-operate-dialog__readonly-input .el-input__inner) {
  color: rgb(51 65 85 / 96%);
  cursor: default;
  -webkit-text-fill-color: rgb(51 65 85 / 96%);
}
</style>
