<script setup lang="tsx">
import { computed, nextTick, ref, watch } from 'vue';
import { ElCol, ElDatePicker, ElFormItem, ElInput, ElRow } from 'element-plus';
import dayjs from 'dayjs';
import { PROJECT_MANAGER_ROLE_CODE } from '@/constants/business';
import { RDMS_OBJECT_DIRECTION_DICT_CODE, RDMS_PROJECT_TYPE_DICT_CODE } from '@/constants/dict';
import {
  fetchCreateProjectWithTeam,
  fetchGetProductOptions,
  fetchGetRoleSimpleList,
  fetchUpdateProject
} from '@/service/api';
import { useDict } from '@/hooks/business/dict';
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';
import ProjectCreateBaseForm, {
  type ProjectCreateBaseForm as ProjectCreateBaseFormModel
} from './project-create-base-form.vue';
import ProjectCreateTeamStep from './project-create-team-step.vue';

defineOptions({ name: 'ProjectOperateDialog' });

interface Props {
  managerUserOptions: Api.SystemManage.UserSimple[];
  rowData?: Api.Project.Project | null;
  /** 新增模式：预填所属产品（来自分组行"+ 新增"入口） */
  presetProduct?: { id: string; name: string } | null;
}

const props = defineProps<Props>();

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

const emit = defineEmits<Emits>();

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

// === 编辑模式（单步） ===
interface EditModel {
  projectCode: string;
  projectName: string;
  directionCode: string;
  projectType: string;
  productId: string | null;
  managerUserId: string | null;
  plannedStartDate: string | null;
  plannedEndDate: string | null;
  projectDesc: string;
}

const { formRef: editFormRef, validate: editValidate } = useForm();
const { createRequiredRule } = useFormRules();
const { getLabel: getDirectionLabel } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);

const editModel = ref<EditModel>(createEditModel());
const editLoading = ref(false);
const submitting = ref(false);

const isEditMode = computed(() => Boolean(props.rowData?.id));
const dialogTitle = computed(() => (isEditMode.value ? '编辑项目' : '新增项目'));

interface ProductOption {
  id: string;
  name: string;
  code?: string;
  directionCode?: string;
}

const productOptions = ref<ProductOption[]>([]);

const managerLabelMap = computed(() => new Map(props.managerUserOptions.map(item => [String(item.id), item.nickname])));

const managerDisplayName = computed(() => {
  const managerUserId = editModel.value.managerUserId;

  if (!managerUserId) {
    return '';
  }

  return managerLabelMap.value.get(String(managerUserId)) || String(managerUserId);
});

const hasAssociatedProduct = computed(() => Boolean(editModel.value.productId));
const directionReadonly = computed(() => hasAssociatedProduct.value);

const selectedProductDirection = computed(() => {
  if (!editModel.value.productId) {
    return '';
  }

  return productOptions.value.find(p => p.id === editModel.value.productId)?.directionCode || '';
});

const effectiveDirectionCode = computed({
  get: () => {
    if (hasAssociatedProduct.value) {
      return selectedProductDirection.value || editModel.value.directionCode;
    }

    return editModel.value.directionCode;
  },
  set: (val: string) => {
    if (!hasAssociatedProduct.value) {
      editModel.value.directionCode = val;
    }
  }
});

const directionDisplayName = computed(() => {
  const directionCode = effectiveDirectionCode.value;

  if (!directionCode) {
    return '';
  }

  return getDirectionLabel(directionCode, directionCode);
});

function parsePlannedDate(value: string | null | undefined) {
  if (!value) {
    return null;
  }

  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? null : date;
}

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

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

function buildEndDateShortcut(text: string, mutator: (date: Date) => void) {
  return {
    text,
    value: () => {
      let startDate = parsePlannedDate(editModel.value.plannedStartDate);

      if (!startDate) {
        startDate = new Date();
        editModel.value.plannedStartDate = dayjs(startDate).format('YYYY-MM-DD');
        window.$message?.info('未选择计划开始日期，已按今日为基准计算');
        nextTick(() => editFormRef.value?.clearValidate('plannedStartDate'));
      }

      const endDate = new Date(startDate.getTime());
      mutator(endDate);
      return endDate;
    }
  };
}

const plannedEndDateShortcuts = [
  buildEndDateShortcut('一星期', date => date.setDate(date.getDate() + 7)),
  buildEndDateShortcut('两星期', date => date.setDate(date.getDate() + 14)),
  buildEndDateShortcut('一个月', date => date.setMonth(date.getMonth() + 1)),
  buildEndDateShortcut('三个月', date => date.setMonth(date.getMonth() + 3)),
  buildEndDateShortcut('半年', date => date.setMonth(date.getMonth() + 6)),
  buildEndDateShortcut('一年', date => date.setFullYear(date.getFullYear() + 1))
];

const editRules = {
  projectName: [createRequiredRule('请输入项目名称')],
  directionCode: [createRequiredRule('请选择项目方向')],
  projectType: [createRequiredRule('请选择项目类型')],
  plannedStartDate: [createRequiredRule('请选择计划开始日期')],
  plannedEndDate: [
    createRequiredRule('请选择计划结束日期'),
    {
      validator: (_rule, value: string | null, callback) => {
        if (!isPlannedDateRangeValid(editModel.value.plannedStartDate, value)) {
          callback(new Error('计划结束日期不能早于计划开始日期'));
          return;
        }

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

function createEditModel(): EditModel {
  return {
    projectCode: '',
    projectName: '',
    directionCode: '',
    projectType: '',
    productId: null,
    managerUserId: null,
    plannedStartDate: null,
    plannedEndDate: null,
    projectDesc: ''
  };
}

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

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

async function loadProductOptions() {
  const { error, data } = await fetchGetProductOptions();

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

  productOptions.value = data.map(item => ({
    id: item.id,
    name: item.name || item.code || item.id,
    code: item.code || '',
    directionCode: item.directionCode || ''
  }));
}

async function handleEditSubmit() {
  await editValidate();

  if (!props.rowData?.id) {
    return;
  }

  const managerUserId = editModel.value.managerUserId;

  if (!managerUserId) {
    return;
  }

  const finalDirectionCode = hasAssociatedProduct.value
    ? selectedProductDirection.value || editModel.value.directionCode
    : editModel.value.directionCode;

  submitting.value = true;

  const { error } = await fetchUpdateProject({
    id: props.rowData.id,
    projectCode: getNullableText(editModel.value.projectCode),
    projectName: editModel.value.projectName.trim(),
    directionCode: finalDirectionCode,
    projectType: editModel.value.projectType,
    productId: editModel.value.productId,
    managerUserId,
    plannedStartDate: editModel.value.plannedStartDate,
    plannedEndDate: editModel.value.plannedEndDate,
    actualStartDate: props.rowData.actualStartDate || null,
    actualEndDate: props.rowData.actualEndDate || null,
    projectDesc: getNullableText(editModel.value.projectDesc)
  });

  submitting.value = false;

  if (error) {
    return;
  }

  window.$message?.success('项目编辑成功');
  closeDialog();
  emit('submitted', props.rowData.id);
}

// === 新增模式（两步向导） ===
const baseFormRef = ref<InstanceType<typeof ProjectCreateBaseForm> | null>(null);
const teamStepRef = ref<InstanceType<typeof ProjectCreateTeamStep> | null>(null);
const currentStep = ref<1 | 2>(1);

// === 新增模式:角色列表(父级加载,下发给 team-step 与批量弹层) ===
const roleOptions = ref<Api.SystemManage.RoleSimple[]>([]);
const roleLoading = ref(false);
const managerRoleError = ref('');

const managerRole = computed(() => roleOptions.value.find(item => item.code === PROJECT_MANAGER_ROLE_CODE) ?? null);

async function loadRoles() {
  roleLoading.value = true;
  managerRoleError.value = '';

  const { data } = await fetchGetRoleSimpleList({ scopeType: 'object', objectType: 'project' });

  roleLoading.value = false;
  roleOptions.value = data ?? [];

  if (!managerRole.value) {
    managerRoleError.value = '未找到项目经理角色,请联系管理员';
  }
}

const createBaseModel = ref<ProjectCreateBaseFormModel>(createBaseInfo());
const draftMembers = ref<Api.Project.CreateProjectMemberParams[]>([]);

function createBaseInfo(): ProjectCreateBaseFormModel {
  return {
    projectCode: '',
    projectName: '',
    directionCode: '',
    projectType: '',
    productId: null,
    managerUserId: null,
    plannedStartDate: null,
    plannedEndDate: null,
    projectDesc: ''
  };
}

async function goNext() {
  const valid = await baseFormRef.value?.validate();

  if (!valid) {
    return;
  }

  currentStep.value = 2;
}

function goPrev() {
  currentStep.value = 1;
}

async function handleCreateSubmit() {
  const baseValid = await baseFormRef.value?.validate();

  if (!baseValid) {
    currentStep.value = 1;
    return;
  }

  const teamValid = await teamStepRef.value?.validate();

  if (!teamValid) {
    return;
  }

  submitting.value = true;

  const payload: Api.Project.CreateProjectWithTeamParams = {
    project: {
      projectCode: getNullableText(createBaseModel.value.projectCode),
      projectName: createBaseModel.value.projectName.trim(),
      directionCode: createBaseModel.value.directionCode,
      projectType: createBaseModel.value.projectType,
      productId: createBaseModel.value.productId,
      managerUserId: createBaseModel.value.managerUserId as string,
      plannedStartDate: createBaseModel.value.plannedStartDate,
      plannedEndDate: createBaseModel.value.plannedEndDate,
      projectDesc: getNullableText(createBaseModel.value.projectDesc)
    },
    members: draftMembers.value
  };

  const { error, data } = await fetchCreateProjectWithTeam(payload);

  submitting.value = false;

  if (error) {
    return;
  }

  window.$message?.success('项目新增成功');
  closeDialog();
  emit('submitted', data);
}

// === 公共：弹框可见性变化时重置 / 加载数据 ===
watch(visible, async value => {
  if (!value) {
    return;
  }

  submitting.value = false;
  currentStep.value = 1;

  if (!isEditMode.value || !props.rowData?.id) {
    editModel.value = createEditModel();
    createBaseModel.value = createBaseInfo();

    if (props.presetProduct) {
      createBaseModel.value.productId = props.presetProduct.id;
    }

    draftMembers.value = [];
    await nextTick();
    await loadRoles();
    editFormRef.value?.clearValidate();
    baseFormRef.value?.clearValidate();
    return;
  }

  editLoading.value = true;

  // 编辑模式继续在主弹框拉产品选项（用于回显所属产品名称）
  await loadProductOptions();

  editLoading.value = false;

  editModel.value = {
    projectCode: props.rowData.projectCode || '',
    projectName: props.rowData.projectName || '',
    directionCode: props.rowData.directionCode || '',
    projectType: props.rowData.projectType || '',
    productId: props.rowData.productId,
    managerUserId: props.rowData.managerUserId || null,
    plannedStartDate: props.rowData.plannedStartDate,
    plannedEndDate: props.rowData.plannedEndDate,
    projectDesc: props.rowData.projectDesc || ''
  };

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

<template>
  <!-- 编辑模式：单步表单（与改造前一致） -->
  <BusinessFormDialog
    v-if="isEditMode"
    v-model="visible"
    :title="dialogTitle"
    preset="md"
    :loading="editLoading"
    :confirm-loading="submitting"
    @confirm="handleEditSubmit"
  >
    <ElForm ref="editFormRef" :model="editModel" :rules="editRules" label-position="top">
      <BusinessFormSection title="项目信息">
        <ElRow :gutter="16">
          <ElCol :span="12">
            <ElFormItem label="项目编码" prop="projectCode">
              <ElInput
                :model-value="editModel.projectCode"
                readonly
                class="project-operate-dialog__readonly-input"
                placeholder="未获取到项目编码"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="项目名称" prop="projectName">
              <ElInput v-model="editModel.projectName" clearable maxlength="128" placeholder="请输入项目名称" />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="所属产品">
              <ElInput
                :model-value="
                  productOptions.find(p => p.id === editModel.productId)?.name ||
                  props.rowData?.productName ||
                  editModel.productId ||
                  '未关联产品'
                "
                readonly
                class="project-operate-dialog__readonly-input"
                placeholder="未关联产品"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="项目方向" prop="directionCode">
              <DictSelect
                v-if="!directionReadonly"
                v-model="effectiveDirectionCode"
                :dict-code="RDMS_OBJECT_DIRECTION_DICT_CODE"
                filterable
                placeholder="请选择项目方向"
              />
              <ElInput
                v-else
                :model-value="directionDisplayName"
                readonly
                class="project-operate-dialog__readonly-input"
                placeholder="未获取到项目方向"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="项目类型" prop="projectType">
              <DictSelect
                v-model="editModel.projectType"
                :dict-code="RDMS_PROJECT_TYPE_DICT_CODE"
                filterable
                placeholder="请选择项目类型"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem>
              <template #label>
                <span class="business-form-label-with-tip">
                  <ElTooltip
                    content="如需调整项目经理，请到项目内的团队管理处处理。"
                    popper-class="business-form-label-tooltip"
                    placement="top-start"
                  >
                    <span class="business-form-label-tip">
                      <icon-fe:question />
                    </span>
                  </ElTooltip>
                  <span>项目经理</span>
                </span>
              </template>
              <ElInput
                :model-value="managerDisplayName"
                readonly
                class="project-operate-dialog__readonly-input"
                placeholder="未获取到项目经理"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="计划开始日期" prop="plannedStartDate">
              <ElDatePicker
                v-model="editModel.plannedStartDate"
                type="date"
                value-format="YYYY-MM-DD"
                placeholder="选择开始日期"
                class="project-operate-dialog__date-picker"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="12">
            <ElFormItem label="计划结束日期" prop="plannedEndDate">
              <ElDatePicker
                v-model="editModel.plannedEndDate"
                type="date"
                value-format="YYYY-MM-DD"
                placeholder="选择结束日期"
                :shortcuts="plannedEndDateShortcuts"
                class="project-operate-dialog__date-picker"
              />
            </ElFormItem>
          </ElCol>
          <ElCol :span="24">
            <ElFormItem label="项目说明" prop="projectDesc">
              <ElInput
                v-model="editModel.projectDesc"
                type="textarea"
                :rows="4"
                maxlength="500"
                show-word-limit
                placeholder="请输入项目说明"
              />
            </ElFormItem>
          </ElCol>
        </ElRow>
      </BusinessFormSection>
    </ElForm>
  </BusinessFormDialog>

  <!-- 新增模式:两步向导(复合内容特例,1080px,左侧概念区 + 右侧步骤面板) -->
  <ElDialog
    v-else
    v-model="visible"
    class="project-create-dialog"
    :title="dialogTitle"
    :close-on-click-modal="false"
    destroy-on-close
    align-center
    width="1080px"
  >
    <div class="project-create-dialog__split">
      <aside class="project-create-dialog__guide">
        <div class="project-create-dialog__guide-hero">
          <div class="project-create-dialog__guide-hero-icon">
            <icon-ep:files />
          </div>
          <div class="project-create-dialog__guide-hero-text">
            <div class="project-create-dialog__guide-hero-title">项目</div>
            <div class="project-create-dialog__guide-hero-sub">需求 · 任务 · 交付 的协同载体</div>
          </div>
        </div>

        <p class="project-create-dialog__guide-lead">
          项目帮助组织持续规划和交付业务价值,围绕计划周期、负责人和团队推进研发工作,串起需求、任务、缺陷和成果。
        </p>

        <section class="project-create-dialog__guide-section">
          <h4>包含</h4>
          <p>需求、执行、任务、工作日志、缺陷、文档、统计报表。</p>
        </section>

        <section class="project-create-dialog__guide-section">
          <h4>参与人</h4>
          <p>项目经理(必填,创建后锁定) · 团队角色(开发 / 测试 / 业务 / 关注人)。</p>
        </section>

        <section class="project-create-dialog__guide-section">
          <h4>命名建议</h4>
          <p>建议使用业务团队约定俗成的简短名称,关联所属产品后会继承产品方向,影响下游归类。</p>
        </section>
      </aside>

      <div class="project-create-dialog__main">
        <div class="project-create-dialog__stepbar">
          <div
            class="project-create-dialog__step"
            :class="{ 'is-active': currentStep === 1, 'is-done': currentStep > 1 }"
          >
            <span class="project-create-dialog__step-index">1</span>
            <span class="project-create-dialog__step-text">
              <strong>基础资料</strong>
            </span>
          </div>
          <div class="project-create-dialog__step" :class="{ 'is-active': currentStep === 2 }">
            <span class="project-create-dialog__step-index">2</span>
            <span class="project-create-dialog__step-text">
              <strong>初始化团队</strong>
            </span>
          </div>
        </div>

        <div class="project-create-dialog__body">
          <div v-show="currentStep === 1" class="project-create-dialog__panel">
            <ProjectCreateBaseForm
              ref="baseFormRef"
              v-model="createBaseModel"
              :manager-user-options="managerUserOptions"
            />
          </div>
          <div v-show="currentStep === 2" class="project-create-dialog__panel">
            <ProjectCreateTeamStep
              ref="teamStepRef"
              :base-info="createBaseModel"
              :user-options="managerUserOptions"
              :role-options="roleOptions"
              :role-loading="roleLoading"
              :manager-role-error="managerRoleError"
              @update:members="draftMembers = $event"
            />
          </div>
        </div>
      </div>
    </div>

    <template #footer>
      <div class="project-create-dialog__footer">
        <span class="project-create-dialog__footer-meta">第 {{ currentStep }} 步，共 2 步</span>
        <ElSpace :size="10">
          <ElButton @click="closeDialog">取消</ElButton>
          <ElButton v-if="currentStep === 2" @click="goPrev">上一步</ElButton>
          <ElButton v-if="currentStep === 1" type="primary" @click="goNext">下一步</ElButton>
          <ElButton v-if="currentStep === 2" type="primary" :loading="submitting" @click="handleCreateSubmit">
            确定
          </ElButton>
        </ElSpace>
      </div>
    </template>
  </ElDialog>
</template>

<style scoped>
:deep(.project-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(.project-operate-dialog__readonly-input .el-input__wrapper:hover),
:deep(.project-operate-dialog__readonly-input.is-focus .el-input__wrapper) {
  box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
}

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

:deep(.project-operate-dialog__date-picker.el-date-editor.el-input) {
  width: 100%;
}

.project-create-dialog :deep(.el-dialog__body) {
  display: flex;
  flex-direction: column;
  padding: 0;
}

.project-create-dialog__split {
  display: grid;
  grid-template-columns: 280px 1fr;
  min-height: 0;
}

.project-create-dialog__guide {
  padding: 28px 24px;
  background: linear-gradient(180deg, #f7f9fc 0%, #fafbfc 100%);
  border-right: 1px solid rgb(229 233 242 / 96%);
  overflow-y: auto;
  max-height: min(720px, calc(100vh - 160px));
}

.project-create-dialog__guide-hero {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid rgb(229 233 242 / 96%);
}

.project-create-dialog__guide-hero-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
  font-size: 22px;
  flex-shrink: 0;
}

.project-create-dialog__guide-hero-text {
  min-width: 0;
}

.project-create-dialog__guide-hero-title {
  font-size: 15px;
  font-weight: 650;
  color: var(--el-text-color-primary);
  line-height: 1.4;
}

.project-create-dialog__guide-hero-sub {
  margin-top: 2px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
  line-height: 1.4;
}

.project-create-dialog__guide-lead {
  margin: 0 0 24px;
  font-size: 13.5px;
  line-height: 1.8;
  color: var(--el-text-color-regular);
}

.project-create-dialog__guide-section + .project-create-dialog__guide-section {
  margin-top: 20px;
}

.project-create-dialog__guide-section h4 {
  margin: 0 0 6px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--el-text-color-primary);
  letter-spacing: 0.4px;
}

.project-create-dialog__guide-section p {
  margin: 0;
  font-size: 13px;
  line-height: 1.75;
  color: var(--el-text-color-regular);
}

.project-create-dialog__main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.project-create-dialog__stepbar {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  padding: 14px 24px;
  border-bottom: 1px solid rgb(229 233 242 / 96%);
  background: #fbfcfe;
}

.project-create-dialog__step {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.project-create-dialog__step-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border: 1px solid rgb(215 222 235 / 96%);
  border-radius: 999px;
  background: #fff;
  color: rgb(119 129 150 / 96%);
  font-size: 13px;
  font-weight: 650;
}

.project-create-dialog__step.is-active .project-create-dialog__step-index,
.project-create-dialog__step.is-done .project-create-dialog__step-index {
  border-color: var(--el-color-primary);
  background: var(--el-color-primary);
  color: #fff;
}

.project-create-dialog__step-text {
  min-width: 0;
}

.project-create-dialog__step-text strong {
  display: block;
  font-size: 14px;
  font-weight: 650;
}

.project-create-dialog__step-text small {
  display: block;
  margin-top: 2px;
  color: rgb(119 129 150 / 96%);
  font-size: 12px;
}

.project-create-dialog__body {
  height: min(520px, calc(100vh - 240px));
  overflow: hidden;
}

.project-create-dialog__panel {
  height: 100%;
  padding: 24px;
  overflow: auto;
  box-sizing: border-box;
}

.project-create-dialog__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.project-create-dialog__footer-meta {
  color: rgb(119 129 150 / 96%);
  font-size: 13px;
}
</style>
