<template>
  <div class="p-2">
    <el-card shadow="never">
      <div class="mb-3 flex items-center justify-between">
        <div class="flex flex-wrap items-center gap-2">
          <el-switch v-model="showActual" active-text="显示实际进度" inactive-text="隐藏实际进度" />
        </div>
        <div>
          <el-button @click="goBack">返回</el-button>
        </div>
      </div>

      <el-descriptions v-loading="loading" :column="3" border size="small" class="mb-3">
        <el-descriptions-item label="项目名称">
          {{ planDetail?.projectName || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="项目经理">
          {{ planDetail?.managerName || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="部门负责人">
          {{ planDetail?.chargeName || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="项目计划状态">
          {{ planStatusLabel }}
        </el-descriptions-item>
        <el-descriptions-item label="任务数量">
          {{ taskList.length }}
        </el-descriptions-item>
        <el-descriptions-item label="计划最晚结束时间">
          {{ lastPlanEndDate }}
        </el-descriptions-item>
      </el-descriptions>

      <el-alert title="任务数据来源于项目阶段，仅供查看。" type="info" show-icon :closable="false" class="mb-3" />

      <el-divider content-position="left">项目甘特图</el-divider>
      <div ref="chartContainerRef" class="gantt-chart" />
      <el-empty v-if="!taskList.length" description="暂无任务数据" />

      <el-divider content-position="left">任务列表</el-divider>
      <el-table :data="taskList" border stripe max-height="420" size="small">
        <el-table-column type="index" width="60" label="序号" align="center" />
        <el-table-column prop="taskName" label="任务名称" min-width="160" show-overflow-tooltip />
        <el-table-column prop="phaseName" label="所属阶段" min-width="120" show-overflow-tooltip />
        <el-table-column prop="ownerName" label="负责人" min-width="120" show-overflow-tooltip />
        <el-table-column prop="planStart" label="计划开始" min-width="120" show-overflow-tooltip />
        <el-table-column prop="planEnd" label="计划结束" min-width="120" show-overflow-tooltip />
        <el-table-column prop="realStart" label="实际开始" min-width="120" show-overflow-tooltip />
        <el-table-column prop="realEnd" label="实际结束" min-width="120" show-overflow-tooltip />
        <el-table-column prop="dependencyLabels" label="依赖任务" min-width="160" show-overflow-tooltip />
        <el-table-column prop="remark" label="备注" min-width="160" show-overflow-tooltip />
      </el-table>
    </el-card>
  </div>
</template>

<script setup lang="ts" name="ErpProjectPlanGantt">
import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import * as echarts from 'echarts';
import { useResizeObserver } from '@vueuse/core';
import { getErpProjectPlan } from '@/api/oa/erp/erpProjectPlan';
import type { ErpProjectPlanVO } from '@/api/oa/erp/erpProjectPlan/types';
import { queryProjectChangeByProjectPlanId } from '@/api/oa/erp/erpProjectChange';

interface GanttTask {
  taskId: string;
  taskName: string;
  phaseName?: string;
  ownerName?: string;
  planStart?: string;
  planEnd?: string;
  realStart?: string;
  realEnd?: string;
  dependencyLabels?: string;
  remark?: string;
  originalPlanStart?: string; // 原计划开始时间
  originalPlanEnd?: string; // 原计划结束时间
  hasChange?: boolean; // 是否有变更
}

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute();
const router = useRouter();
const { project_plan_status, project_phases } = toRefs<any>(proxy?.useDict('project_plan_status', 'project_phases'));

const loading = ref(false);
const showActual = ref(true);
const planDetail = ref<ErpProjectPlanVO | null>(null);
const taskList = ref<GanttTask[]>([]);

const chartContainerRef = ref<HTMLDivElement | null>(null);
const chartInstance = ref<echarts.ECharts | null>(null);

// 构建阶段字典映射，便于展示阶段中文名称
const phaseMap = computed<Record<string, string>>(() => {
  const map: Record<string, string> = {};
  (project_phases?.value || []).forEach((item: any) => {
    map[item.value] = item.label;
  });
  return map;
});

const statusMap = computed<Record<string, string>>(() => {
  const map: Record<string, string> = {};
  (project_plan_status?.value || []).forEach((item: any) => {
    map[item.value] = item.label;
  });
  return map;
});

const planStatusLabel = computed(() => {
  if (!planDetail.value?.projectPlanStatus) {
    return '-';
  }
  return statusMap.value[planDetail.value.projectPlanStatus] || planDetail.value.projectPlanStatus;
});

const lastPlanEndDate = computed(() => {
  if (!taskList.value.length) {
    return '-';
  }
  let maxTs: number | null = null;
  taskList.value.forEach((task) => {
    const ts = toTimestamp(task.planEnd);
    if (ts !== null) {
      if (maxTs === null || ts > maxTs) {
        maxTs = ts;
      }
    }
  });
  if (maxTs === null) {
    return '-';
  }
  return formatDisplayDate(new Date(maxTs));
});

const projectPlanId = computed(() => route.params.projectPlanId as string);

const renderGanttItem = (params: any, api: any) => {
  const categoryIndex = api.value(0);
  const start = api.coord([api.value(1), categoryIndex]);
  const end = api.coord([api.value(2), categoryIndex]);
  const height = api.size([0, 1])[1] * 0.55;
  const rectShape = echarts.graphic.clipRectByRect(
    {
      x: Math.min(start[0], end[0]),
      y: start[1] - height / 2,
      width: Math.abs(end[0] - start[0]),
      height
    },
    {
      x: params.coordSys.x,
      y: params.coordSys.y,
      width: params.coordSys.width,
      height: params.coordSys.height
    }
  );
  if (!rectShape) {
    return null;
  }
  return {
    type: 'rect',
    transition: ['shape'],
    shape: rectShape,
    style: api.style()
  };
};

const updateChart = () => {
  if (!chartInstance.value) {
    return;
  }
  if (!taskList.value.length) {
    chartInstance.value.clear();
    chartInstance.value.setOption({
      tooltip: { trigger: 'axis' },
      xAxis: { type: 'time' },
      yAxis: { type: 'category', data: [] },
      series: []
    });
    return;
  }

  const categories = taskList.value.map((task) => task.taskName || '未命名任务');
  let min = Number.POSITIVE_INFINITY;
  let max = Number.NEGATIVE_INFINITY;

  const planBarData: any[] = [];
  const planPointData: any[] = [];

  taskList.value.forEach((task, index) => {
    const start = toTimestamp(task.planStart);
    const end = toTimestamp(task.planEnd);
    if (start === null || end === null) {
      return;
    }
    // 同一天的任务使用散点展示，避免零宽度矩形不可见
    if (end <= start) {
      min = Math.min(min, start);
      max = Math.max(max, start);
      planPointData.push({
        name: task.taskName,
        value: [start, index],
        task
      });
    } else {
      min = Math.min(min, start);
      max = Math.max(max, end);
      planBarData.push({
        name: task.taskName,
        value: [index, start, end],
        task
      });
    }
  });

  const actualBarData: any[] = [];
  const actualPointData: any[] = [];

  if (showActual.value) {
    taskList.value.forEach((task, index) => {
      const start = toTimestamp(task.realStart);
      const end = toTimestamp(task.realEnd);
      if (start === null || end === null) {
        return;
      }
      // 实际进度同一天也使用散点展示
      if (end <= start) {
        min = Math.min(min, start);
        max = Math.max(max, start);
        actualPointData.push({
          name: `${task.taskName}-实际`,
          value: [start, index],
          task
        });
      } else {
        min = Math.min(min, start);
        max = Math.max(max, end);
        actualBarData.push({
          name: `${task.taskName}-实际`,
          value: [index, start, end],
          task
        });
      }
    });
  }

  if (min === Number.POSITIVE_INFINITY || max === Number.NEGATIVE_INFINITY) {
    const now = Date.now();
    min = now - 7 * 24 * 3600 * 1000;
    max = now + 7 * 24 * 3600 * 1000;
  }

  const series: any[] = [];
  if (planBarData.length) {
    series.push({
      name: '计划进度',
      type: 'custom',
      renderItem: renderGanttItem,
      itemStyle: { color: '#91cc75', opacity: 0.9 },
      encode: { x: [1, 2], y: 0 },
      data: planBarData
    });
  }
  if (planPointData.length) {
    series.push({
      name: '计划进度(单日)',
      type: 'scatter',
      symbolSize: 10,
      itemStyle: { color: '#91cc75', opacity: 0.9 },
      data: planPointData
    });
  }
  if (actualBarData.length) {
    series.push({
      name: '实际进度',
      type: 'custom',
      renderItem: renderGanttItem,
      itemStyle: { color: '#5470c6', opacity: 0.75 },
      encode: { x: [1, 2], y: 0 },
      data: actualBarData
    });
  }
  if (actualPointData.length) {
    series.push({
      name: '实际进度(单日)',
      type: 'scatter',
      symbolSize: 10,
      itemStyle: { color: '#5470c6', opacity: 0.75 },
      data: actualPointData
    });
  }

  chartInstance.value.setOption(
    {
      tooltip: {
        trigger: 'item',
        formatter: (params: any) => {
          const task: GanttTask | undefined = params.data?.task;
          if (!task) {
            return params.name;
          }
          let planText = `计划：${task.planStart || '-'} 至 ${task.planEnd || '-'}`;
          if (task.hasChange) {
            planText += `<br/><span style="color:#e6a23c;font-size:12px;">(最新变更) 原计划：${task.originalPlanStart || '-'} 至 ${task.originalPlanEnd || '-'}</span>`;
          }
          const actualText = `实际：${task.realStart || '-'} 至 ${task.realEnd || '-'}`;
          return [params.marker + (task.taskName || '未命名任务'), planText, actualText].join('<br/>');
        }
      },
      legend: {
        data: series.map((s) => s.name),
        top: 0
      },
      grid: {
        left: 80,
        right: 40,
        top: 60,
        bottom: 60
      },
      xAxis: {
        type: 'time',
        min: min - 24 * 3600 * 1000,
        max: max + 24 * 3600 * 1000,
        axisLabel: {
          formatter: (value: number) => formatDisplayDate(new Date(value))
        }
      },
      yAxis: {
        type: 'category',
        data: categories,
        axisTick: { alignWithLabel: true }
      },
      dataZoom: [
        { type: 'inside', xAxisIndex: 0, filterMode: 'weakFilter' },
        { type: 'slider', xAxisIndex: 0, filterMode: 'weakFilter' }
      ],
      series
    },
    true
  );
};

watch(
  () => taskList.value,
  () => {
    updateChart();
  }
);

watch(showActual, () => {
  updateChart();
});

const buildTaskListFromStages = (stages: any[] = [], changeMap: Map<any, any> = new Map()): GanttTask[] =>
  stages.map((stage) => {
    const originalStart = normalizeDate(stage.planStartTime);
    const originalEnd = normalizeDate(stage.planEndTime);

    // 检查是否有变更
    const changeInfo = changeMap.get(stage.planStageId);
    const hasChange = !!changeInfo;

    // 如果有变更，优先使用变更后的时间
    const planStart = hasChange && changeInfo.changedStart ? normalizeDate(changeInfo.changedStart) : originalStart;
    const planEnd = hasChange && changeInfo.changedEnd ? normalizeDate(changeInfo.changedEnd) : originalEnd;

    return {
      taskId: String(stage.planStageId ?? generateTaskId()),
      taskName: phaseMap.value[stage.projectPhases as string] || stage.projectPhases || stage.scheduleRemark || '未命名阶段',
      phaseName: phaseMap.value[stage.projectPhases as string] || '-',
      ownerName: planDetail.value?.managerName,
      planStart,
      planEnd,
      realStart: normalizeDate(stage.realStartTime),
      realEnd: normalizeDate(stage.realEndTime),
      dependencyLabels: Array.isArray(stage.dependencyNames) ? stage.dependencyNames.join('、') : stage.dependencyNames || '-',
      remark: stage.scheduleRemark || '-',
      originalPlanStart: originalStart,
      originalPlanEnd: originalEnd,
      hasChange
    };
  });

const loadPlanDetail = async () => {
  if (!projectPlanId.value || projectPlanId.value === '0') {
    proxy?.$modal.msgWarning('请先保存项目计划，再查看甘特图');
    return;
  }
  loading.value = true;
  try {
    // 并行加载项目计划和变更记录
    const [res, changeRes] = await Promise.all([
      getErpProjectPlan(projectPlanId.value),
      queryProjectChangeByProjectPlanId(projectPlanId.value).catch(() => ({ data: [] }))
    ]);

    planDetail.value = res.data;

    // 处理变更记录，找到最后一次变更
    const changeList = changeRes.data || [];
    const changeMap = new Map();

    if (changeList.length > 0) {
      // 假设最后一条是最新变更（后端按ID或时间排序通常是这样，如果不确定可以先sort）
      // 这里简单取列表最后一条
      const lastChange = changeList[changeList.length - 1];
      if (lastChange && lastChange.progressList) {
        lastChange.progressList.forEach((p: any) => {
          if (p.planStageId) {
            changeMap.set(p.planStageId, p);
          }
        });
      }
    }

    await nextTick();
    taskList.value = buildTaskListFromStages(res.data.planStageList || [], changeMap);
    updateChart();
  } catch (error) {
    proxy?.$modal.msgError('获取项目计划数据失败');
    console.error(error);
  } finally {
    loading.value = false;
  }
};

const generateTaskId = () => {
  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
    return crypto.randomUUID();
  }
  return `task_${Date.now()}_${Math.floor(Math.random() * 10000)}`;
};

const goBack = () => {
  router.back();
};

const normalizeDate = (value?: string | null) => {
  if (!value) {
    return undefined;
  }
  const trimmed = value.trim();
  if (!trimmed) {
    return undefined;
  }
  return trimmed.length > 10 ? trimmed.slice(0, 10) : trimmed;
};

const toTimestamp = (value?: string) => {
  const dateText = normalizeDate(value);
  if (!dateText) {
    return null;
  }
  const time = new Date(`${dateText}T00:00:00`).getTime();
  if (Number.isNaN(time)) {
    return null;
  }
  return time;
};

const formatDisplayDate = (date: Date) => {
  if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
    return '-';
  }
  const year = date.getFullYear();
  const month = `${date.getMonth() + 1}`.padStart(2, '0');
  const day = `${date.getDate()}`.padStart(2, '0');
  return `${year}-${month}-${day}`;
};

onMounted(async () => {
  if (chartContainerRef.value) {
    chartInstance.value = echarts.init(chartContainerRef.value);
  }
  if (chartContainerRef.value) {
    useResizeObserver(chartContainerRef, () => {
      chartInstance.value?.resize();
    });
  }
  await loadPlanDetail();
  updateChart();
});

onBeforeUnmount(() => {
  chartInstance.value?.dispose();
});
</script>

<style scoped>
.gantt-chart {
  width: 100%;
  min-height: 420px;
}
</style>
