<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue';
import dayjs from 'dayjs';
import { fetchGetRequirement, fetchGetRequirementModuleTree, fetchUpdateRequirement } from '@/service/api';
import { useForm, useFormRules } from '@/hooks/common/form';
import { useDict } from '@/hooks/business/dict';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
import DictSelect from '@/components/custom/dict-select.vue';
import ReadonlyField from '@/components/custom/readonly-field.vue';
import MemberSelectOption from './member-select-option.vue';

defineOptions({ name: 'RequirementDetailDialog' });

type DialogMode = 'view' | 'edit';

interface Props {
  mode: DialogMode;
  requirement: Api.Product.Requirement | null;
  productId: string;
  memberOptions: Api.Product.ProductMember[];
  categoryDictCode: string;
  priorityDictCode: string;
}

const props = defineProps<Props>();

interface Emits {
  (e: 'submitted', requirementId?: string): void;
}

const emit = defineEmits<Emits>();

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

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

const { getLabel: getCategoryLabel } = useDict(() => props.categoryDictCode);
const { getLabel: getPriorityLabel, enabledDictData: priorityDictData } = useDict(() => props.priorityDictCode);

const priorityOptions = computed(() => {
  return priorityDictData.value.map(item => ({
    label: item.label,
    value: Number(item.value)
  }));
});

interface Model {
  title: string;
  description: string;
  reviewRequired: number;
  completionDate: string;
  moduleId: string;
  category: string;
  priority: number | null;
  proposerId: string;
  currentHandlerUserId: string;
  implementProjectId: string | null;
  sort: number;
  lastStatusReason: string;
}

const loading = ref(false);
const submitting = ref(false);
const moduleTree = ref<Api.Product.RequirementModule[]>([]);

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

const isViewMode = computed(() => props.mode === 'view');
const isEditMode = computed(() => props.mode === 'edit');
const dialogTitle = computed(() => {
  if (isViewMode.value) {
    return '查看需求';
  }
  return '编辑需求';
});

const memberUserOptions = computed(() => {
  return props.memberOptions.filter(m => m.status === 0);
});

const memberLabelMap = computed(() => {
  return new Map(memberUserOptions.value.map(item => [String(item.userId), item.userNickname]));
});

const moduleLabelMap = computed(() => {
  const map = new Map<string | undefined, string>();
  function traverse(modules: Api.Product.RequirementModule[]) {
    for (const module of modules) {
      map.set(module.id, module.moduleName);
      if (module.children?.length) {
        traverse(module.children);
      }
    }
  }
  traverse(moduleTree.value);
  return map;
});

const moduleTreeProps = {
  label: 'moduleName',
  value: 'id',
  children: 'children'
};

const reviewRequiredOptions = [
  { label: '不需要', value: 0 },
  { label: '需要', value: 1 }
];

const rules = computed(() => {
  const baseRules: Record<string, App.Global.FormRule[]> = {
    title: isEditMode.value ? [createRequiredRule('请输入需求标题')] : [],
    category: isEditMode.value ? [createRequiredRule('请选择分类')] : [],
    priority: isEditMode.value ? [createRequiredRule('请选择优先级')] : [],
    proposerId: isEditMode.value ? [createRequiredRule('请选择提出人')] : [],
    currentHandlerUserId: isEditMode.value ? [createRequiredRule('请选择负责人')] : [],
    completionDate: isEditMode.value ? [createRequiredRule('请选择预期完成时间')] : []
  };

  return baseRules;
});

function createDefaultModel(): Model {
  return {
    title: '',
    description: '',
    reviewRequired: 0,
    completionDate: '',
    moduleId: '0',
    category: '',
    priority: 1,
    proposerId: '',
    currentHandlerUserId: '',
    implementProjectId: null,
    sort: 0,
    lastStatusReason: ''
  };
}

function getNullableText(value?: string | null) {
  return value?.trim() || null;
}

function closeDialog() {
  visible.value = false;
}

async function handleSubmit() {
  await validate();

  if (!props.productId || !props.requirement?.id) {
    return;
  }

  submitting.value = true;

  const updatePayload: Api.Product.UpdateRequirementParams = {
    id: props.requirement.id,
    productId: props.productId,
    moduleId: model.value.moduleId || '0',
    reviewRequired: model.value.reviewRequired as Api.Product.RequirementReviewRequired,
    title: model.value.title.trim(),
    description: getNullableText(model.value.description),
    category: model.value.category,
    priority: Number(model.value.priority) as Api.Product.RequirementPriority,
    proposerId: model.value.proposerId,
    currentHandlerUserId: model.value.currentHandlerUserId,
    implementProjectId: model.value.implementProjectId,
    completionDate: model.value.completionDate,
    sort: model.value.sort
  };

  const { error } = await fetchUpdateRequirement(updatePayload);

  submitting.value = false;

  if (error) {
    return;
  }

  window.$message?.success('需求更新成功');
  closeDialog();
  emit('submitted', props.requirement.id);
}

async function loadModuleTree() {
  if (!props.productId) {
    moduleTree.value = [];
    return;
  }

  const { error, data } = await fetchGetRequirementModuleTree(props.productId);

  if (error || !data) {
    moduleTree.value = [];
    return;
  }

  moduleTree.value = data;
}

async function loadRequirementDetail() {
  if (!props.productId || !props.requirement?.id) {
    return;
  }

  loading.value = true;

  const { error, data } = await fetchGetRequirement(props.requirement.id, props.productId);

  loading.value = false;

  if (error || !data) {
    return;
  }

  model.value = {
    title: data.title || '',
    description: data.description || '',
    reviewRequired: data.reviewRequired ?? 0,
    completionDate: data.completionDate || '',
    moduleId: data.moduleId || '0',
    category: data.category || '',
    priority: data.priority ?? null,
    proposerId: data.proposerId || '',
    currentHandlerUserId: data.currentHandlerUserId || '',
    implementProjectId: data.implementProjectId || null,
    sort: data.sort ?? 0,
    lastStatusReason: data.lastStatusReason || ''
  };
}

watch(
  () => visible.value,
  async value => {
    if (!value) {
      return;
    }

    await loadModuleTree();

    if (props.requirement?.id) {
      await loadRequirementDetail();
    }

    await nextTick();
    formRef.value?.clearValidate();
  }
);
</script>

<template>
  <BusinessFormDialog
    v-model="visible"
    :title="dialogTitle"
    preset="lg"
    :loading="loading"
    :confirm-loading="submitting"
    :show-footer="isEditMode"
    @confirm="handleSubmit"
  >
    <ElForm ref="formRef" :model="model" :rules="rules" label-position="top">
      <ElRow :gutter="16">
        <ElCol :span="12">
          <ElFormItem label="标题" prop="title">
            <template v-if="isViewMode">
              <ReadonlyField :value="model.title" />
            </template>
            <ElInput v-else v-model="model.title" clearable maxlength="256" placeholder="请输入需求标题" />
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="预期完成时间" prop="completionDate" style="width: 100%">
            <template v-if="isViewMode">
              <ReadonlyField
                :value="model.completionDate ? dayjs(Number(model.completionDate)).format('YYYY-MM-DD HH:mm:ss') : '--'"
              />
            </template>
            <ElDatePicker
              v-else
              v-model="model.completionDate"
              type="datetime"
              class="w-full"
              placeholder="选择预期完成时间"
              value-format="x"
              style="width: 100%"
            />
          </ElFormItem>
        </ElCol>
        <ElCol :span="24">
          <ElFormItem label="描述">
            <template v-if="isViewMode">
              <div class="readonly-textarea">
                {{ model.description || '--' }}
              </div>
            </template>
            <ElInput
              v-else
              v-model="model.description"
              type="textarea"
              :rows="6"
              maxlength="2000"
              show-word-limit
              placeholder="请输入需求描述"
            />
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="是否需要评审">
            <ReadonlyField :value="reviewRequiredOptions.find(opt => opt.value === model.reviewRequired)?.label" />
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="模块">
            <template v-if="isViewMode">
              <ReadonlyField :value="moduleLabelMap.get(model.moduleId) || '--'" />
            </template>
            <ElTreeSelect
              v-else
              v-model="model.moduleId"
              :data="moduleTree"
              :props="moduleTreeProps"
              class="w-full"
              check-strictly
              :render-after-expand="false"
              placeholder="请选择所属模块"
            />
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="分类" prop="category">
            <template v-if="isViewMode">
              <ReadonlyField :value="getCategoryLabel(model.category) || '--'" />
            </template>
            <DictSelect
              v-else
              v-model="model.category"
              :dict-code="categoryDictCode"
              filterable
              placeholder="请选择分类"
            />
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="优先级" prop="priority">
            <template v-if="isViewMode">
              <ReadonlyField
                :value="model.priority !== null ? getPriorityLabel(String(model.priority)) || '--' : '--'"
              />
            </template>
            <ElSelect v-else v-model="model.priority" class="w-full" filterable placeholder="请选择优先级">
              <ElOption v-for="item in priorityOptions" :key="item.value" :label="item.label" :value="item.value" />
            </ElSelect>
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="提出人" prop="proposerId">
            <template v-if="isViewMode">
              <ReadonlyField :value="memberLabelMap.get(model.proposerId) || '--'" />
            </template>
            <ElSelect v-else v-model="model.proposerId" class="w-full" filterable placeholder="请选择提出人">
              <ElOption
                v-for="item in memberUserOptions"
                :key="item.userId"
                :label="item.userNickname"
                :value="item.userId"
              >
                <MemberSelectOption :nickname="item.userNickname" :role-name="item.roleName" />
              </ElOption>
            </ElSelect>
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="负责人" prop="currentHandlerUserId">
            <template v-if="isViewMode">
              <ReadonlyField :value="memberLabelMap.get(model.currentHandlerUserId) || '--'" />
            </template>
            <ElSelect v-else v-model="model.currentHandlerUserId" class="w-full" filterable placeholder="请选择负责人">
              <ElOption
                v-for="item in memberUserOptions"
                :key="item.userId"
                :label="item.userNickname"
                :value="item.userId"
              >
                <MemberSelectOption :nickname="item.userNickname" :role-name="item.roleName" />
              </ElOption>
            </ElSelect>
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="实现项目">
            <ReadonlyField :value="model.implementProjectId || '--'" />
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="排序值">
            <template v-if="isViewMode">
              <ReadonlyField :value="model.sort" />
            </template>
            <ElInputNumber v-else v-model="model.sort" class="w-full" :min="0" :max="9999" placeholder="请输入排序值" />
          </ElFormItem>
        </ElCol>
        <ElCol v-if="isViewMode && model.lastStatusReason" :span="24">
          <ElFormItem label="状态变更原因">
            <div class="readonly-textarea">
              {{ model.lastStatusReason }}
            </div>
          </ElFormItem>
        </ElCol>
      </ElRow>
    </ElForm>
  </BusinessFormDialog>
</template>

<style scoped>
.readonly-textarea {
  box-sizing: border-box;
  width: 100%;
  min-height: 100px;
  padding: 8px 12px;
  border-radius: 4px;
  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;
  color: rgb(51 65 85 / 96%);
  font-size: 14px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
}
</style>
