<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import dayjs from 'dayjs';
import { OBJECT_CONTEXT_QUERY_KEY } from '@/constants/object-context';
import { type ECOption, useEcharts } from '@/hooks/common/echarts';
import { getWorkbenchItemColor } from '../composables/use-workbench-colors';
import {
  type WorkbenchTeamWorklogView,
  type WorkbenchWeekWorklogView,
  type WorkbenchWorklogDistributionItem,
  buildWorkbenchTeamWorklogView,
  buildWorkbenchWeekWorklogView
} from '../homepage';
import { workbenchMyWeekWorklogMock, workbenchTeamWorklogMock } from '../mock';
import WorkbenchModuleCard from './workbench-module-card.vue';

defineOptions({ name: 'WorkbenchMyWeekWorklog' });

interface Props {
  editing?: boolean;
  collapsed?: boolean;
}
withDefaults(defineProps<Props>(), { editing: false, collapsed: false });
defineEmits<{ (e: 'hide'): void; (e: 'toggle-collapse'): void }>();

const router = useRouter();

// EP type='week' 默认 firstDayOfWeek=7，从日历点选时返回当周"周日"。
// 我们按 ISO 周（周一-周日）存储；遇到周日 +1 天再 startOf('isoWeek')，避免回退到上一周。
function resolveIsoWeekStart(weekDate: Date | null) {
  if (!weekDate) return null;
  const picked = dayjs(weekDate);
  if (!picked.isValid()) return null;
  const aligned = picked.isoWeekday() === 7 ? picked.add(1, 'day') : picked;
  return aligned.startOf('isoWeek');
}

const weekDateShortcuts = [
  { text: '本周', value: () => dayjs().startOf('isoWeek').toDate() },
  { text: '上周', value: () => dayjs().subtract(1, 'week').startOf('isoWeek').toDate() }
];

const selectedWeekDate = ref<Date | null>(dayjs().startOf('isoWeek').toDate());

const selectedWeekStart = computed(() => {
  const aligned = resolveIsoWeekStart(selectedWeekDate.value);
  return aligned ? aligned.format('YYYY-MM-DD') : '';
});

type TabKey = 'my' | 'team';
const activeTab = ref<TabKey>('my');

// ============ 我的工时 ============

const myView = computed<WorkbenchWeekWorklogView | null>(() => {
  if (!selectedWeekStart.value) return null;
  if (selectedWeekStart.value === workbenchMyWeekWorklogMock.current.weekStart) {
    return buildWorkbenchWeekWorklogView(workbenchMyWeekWorklogMock.current);
  }
  if (selectedWeekStart.value === workbenchMyWeekWorklogMock.previous.weekStart) {
    return buildWorkbenchWeekWorklogView(workbenchMyWeekWorklogMock.previous);
  }
  return null;
});

const isCurrentWeek = computed(() => selectedWeekStart.value === workbenchMyWeekWorklogMock.current.weekStart);

const totalLabel = computed(() => (isCurrentWeek.value ? '累计' : '上周累计'));

const deltaInfo = computed(() => {
  if (!myView.value) return null;
  const { delta, completionRate } = myView.value;
  if (isCurrentWeek.value) {
    if (delta >= 0) return { text: `领先目标 +${delta}h`, tone: 'success' as const };
    return { text: `落后目标 ${delta}h`, tone: 'danger' as const };
  }
  return { text: `达成 ${completionRate}%`, tone: completionRate >= 100 ? ('success' as const) : ('muted' as const) };
});

// 每日柱图的"按天/按周"分色（与项目色无关，保留本地常量）
const DAY_BAR_COLOR = '#409EFF';
const WEEK_BAR_COLOR = '#A0CFFF';

interface DistributionRow extends WorkbenchWorklogDistributionItem {
  color: string;
}

const distributionRows = computed<DistributionRow[]>(() => {
  const list = myView.value?.distribution ?? [];
  return list.map(item => ({ ...item, color: getWorkbenchItemColor(item.key, item.kind) }));
});

function handleDistributionClick(item: WorkbenchWorklogDistributionItem) {
  if (item.kind === 'project' && item.projectId) {
    router.push({
      path: '/project/project/execution',
      query: { [OBJECT_CONTEXT_QUERY_KEY]: item.projectId }
    });
    return;
  }
  if (item.kind === 'personal') {
    router.push({ path: '/personal-center/my-item' });
  }
}

function buildPieOption(): ECOption {
  const list = distributionRows.value;
  return {
    tooltip: { trigger: 'item', formatter: '{b}: {c}h ({d}%)' },
    series: [
      {
        type: 'pie',
        radius: ['38%', '58%'],
        center: ['50%', '52%'],
        avoidLabelOverlap: true,
        minAngle: 6,
        label: {
          show: true,
          formatter: (params: any) => `${params.name}\n${params.percent}%`,
          color: '#475569',
          fontSize: 11,
          lineHeight: 14
        },
        labelLine: {
          show: true,
          length: 6,
          length2: 8,
          smooth: false
        },
        emphasis: {
          scale: true,
          scaleSize: 4,
          label: { fontWeight: 700 }
        },
        data: list.map(item => ({
          name: item.label,
          value: item.hours,
          itemStyle: { color: item.color },
          cursor: item.kind === 'other' ? 'default' : 'pointer'
        }))
      }
    ]
  };
}

function buildMyBarOption(): ECOption {
  const v = myView.value;
  return {
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (rawParams: any) => {
        const params = Array.isArray(rawParams) ? rawParams : [rawParams];
        const dayName = params[0]?.axisValue ?? '';
        const dayPart = params.find((p: any) => p.seriesName === '按天填')?.value ?? 0;
        const weekPart = params.find((p: any) => p.seriesName === '按周均分')?.value ?? 0;
        const total = Number(dayPart) + Number(weekPart);
        return `周${dayName}：${total}h<br/>按天填 ${dayPart}h<br/>按周均分 ${weekPart}h`;
      }
    },
    grid: { left: 28, right: 8, top: 16, bottom: 24, containLabel: false },
    xAxis: {
      type: 'category',
      data: ['一', '二', '三', '四', '五'],
      axisTick: { show: false },
      axisLine: { lineStyle: { color: '#e5e7eb' } },
      axisLabel: { color: '#6b7280', fontSize: 11 }
    },
    yAxis: {
      type: 'value',
      splitLine: { lineStyle: { color: '#f3f4f6' } },
      axisLabel: { color: '#9ca3af', fontSize: 10 }
    },
    series: [
      {
        name: '按天填',
        type: 'bar',
        stack: 'total',
        barWidth: 18,
        data: v?.dailyByDay ?? [],
        itemStyle: { color: DAY_BAR_COLOR, borderRadius: [0, 0, 2, 2] }
      },
      {
        name: '按周均分',
        type: 'bar',
        stack: 'total',
        barWidth: 18,
        data: v?.dailyByWeekAvg ?? [],
        itemStyle: { color: WEEK_BAR_COLOR, borderRadius: [2, 2, 0, 0] }
      }
    ]
  };
}

const { domRef: pieRef, updateOptions: updatePie } = useEcharts(buildPieOption, {
  onRender(chart) {
    chart.on('click', (params: any) => {
      const item = myView.value?.distribution[params.dataIndex];
      if (item) handleDistributionClick(item);
    });
  }
});

const { domRef: myBarRef, updateOptions: updateMyBar } = useEcharts(buildMyBarOption, { onRender() {} });

// ============ 团队工时 ============

const teamView = computed<WorkbenchTeamWorklogView | null>(() => {
  if (!selectedWeekStart.value) return null;
  if (selectedWeekStart.value === workbenchTeamWorklogMock.current.weekStart) {
    return buildWorkbenchTeamWorklogView(workbenchTeamWorklogMock.current);
  }
  if (selectedWeekStart.value === workbenchTeamWorklogMock.previous.weekStart) {
    return buildWorkbenchTeamWorklogView(workbenchTeamWorklogMock.previous);
  }
  return null;
});

const teamSeriesWithColor = computed(() =>
  (teamView.value?.seriesMatrix ?? []).map(s => ({ ...s, color: getWorkbenchItemColor(s.key, s.kind) }))
);

function buildTeamBarOption(): ECOption {
  const v = teamView.value;
  if (!v) return {};
  const colored = teamSeriesWithColor.value;
  return {
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (rawParams: any) => {
        const params = Array.isArray(rawParams) ? rawParams : [rawParams];
        if (!params.length) return '';
        const name = params[0].axisValue as string;
        const total = params.reduce((s: number, p: any) => s + (Number(p.value) || 0), 0);
        const lines = params
          .filter((p: any) => Number(p.value) > 0)
          .map((p: any) => `${p.marker}${p.seriesName} <b style="margin-left:6px">${p.value}h</b>`)
          .join('<br/>');
        return `<div style="font-weight:600;margin-bottom:4px">${name} · ${total}h</div>${lines}`;
      }
    },
    legend: {
      type: 'scroll',
      bottom: 0,
      itemWidth: 10,
      itemHeight: 10,
      textStyle: { color: '#6b7280', fontSize: 11 }
    },
    grid: { left: 32, right: 12, top: 16, bottom: 40, containLabel: false },
    xAxis: {
      type: 'category',
      data: v.members.map(m => m.memberName),
      axisTick: { show: false },
      axisLine: { lineStyle: { color: '#e5e7eb' } },
      axisLabel: { color: '#6b7280', fontSize: 11 }
    },
    yAxis: {
      type: 'value',
      splitLine: { lineStyle: { color: '#f3f4f6' } },
      axisLabel: { color: '#9ca3af', fontSize: 10, formatter: '{value}h' }
    },
    series: colored.map((s, i) => ({
      name: s.label,
      type: 'bar',
      stack: 'member',
      barWidth: 22,
      data: s.data,
      itemStyle: {
        color: s.color,
        borderRadius: i === colored.length - 1 ? [3, 3, 0, 0] : 0
      }
    }))
  };
}

const { domRef: teamBarRef, updateOptions: updateTeamBar } = useEcharts(buildTeamBarOption, { onRender() {} });

// ============ 数据 / 切换变化时刷新 echarts ============

watch(myView, () => {
  updatePie((_, factory) => factory());
  updateMyBar((_, factory) => factory());
});

watch(teamView, () => {
  updateTeamBar((_, factory) => factory());
});

// 切 tab 后等 v-show 容器渲染再触发 echarts 重画（避免 display:none → block 切换时尺寸残留为 0）
watch(activeTab, async tab => {
  await nextTick();
  if (tab === 'my') {
    updatePie((_, factory) => factory());
    updateMyBar((_, factory) => factory());
  } else {
    updateTeamBar((_, factory) => factory());
  }
});
</script>

<template>
  <WorkbenchModuleCard
    title="工时"
    icon="mdi:timer-outline"
    :editing="editing"
    :collapsed="collapsed"
    @hide="$emit('hide')"
    @toggle-collapse="$emit('toggle-collapse')"
  >
    <div class="ww-tabbar">
      <ElTabs v-model="activeTab" class="ww-tabs">
        <ElTabPane label="我的工时" name="my" />
        <ElTabPane label="团队工时" name="team" />
      </ElTabs>
      <ElDatePicker
        v-model="selectedWeekDate"
        type="week"
        format="YYYY[年第]ww[周]"
        placeholder="选择周次"
        :shortcuts="weekDateShortcuts"
        :clearable="false"
        size="small"
        class="ww-week-picker"
      />
    </div>

    <!-- ============ 我的工时 tab ============ -->
    <div v-show="activeTab === 'my'">
      <template v-if="myView">
        <div class="ww-headline">
          <div class="ww-section-title">
            <SvgIcon icon="mdi:chart-donut" class="ww-section-icon" />
            <span>工时分布</span>
          </div>
          <div class="ww-section-title">
            <SvgIcon icon="mdi:calendar-week" class="ww-section-icon" />
            <span>每日工时</span>
          </div>
        </div>

        <div class="ww-grid">
          <div class="ww-block">
            <div class="ww-pie-wrap">
              <div ref="pieRef" class="ww-pie" />
            </div>
          </div>

          <div class="ww-block">
            <div ref="myBarRef" class="ww-bar" />
            <div class="ww-bar-legend">
              <span class="ww-bar-legend__item">
                <span class="ww-bar-legend__swatch" :style="{ background: DAY_BAR_COLOR }" />
                按天填
              </span>
              <span class="ww-bar-legend__item">
                <span class="ww-bar-legend__swatch" :style="{ background: WEEK_BAR_COLOR }" />
                按周均分
              </span>
            </div>
          </div>
        </div>

        <div class="ww-footer">
          <span>
            {{ totalLabel }}
            <b>{{ myView.totalHours }}h</b>
            / {{ myView.target }}h
          </span>
          <span v-if="deltaInfo" :class="`ww-footer__delta is-${deltaInfo.tone}`">{{ deltaInfo.text }}</span>
        </div>
      </template>
      <ElEmpty v-else description="该周无工时数据" :image-size="60" />
    </div>

    <!-- ============ 团队工时 tab ============ -->
    <div v-show="activeTab === 'team'">
      <template v-if="teamView">
        <div class="tw-kpis">
          <div class="tw-kpi">
            <span class="tw-kpi__label">填报率</span>
            <span class="tw-kpi__value">
              {{ teamView.fillRate }}
              <span class="tw-kpi__unit">%</span>
            </span>
            <span class="tw-kpi__sub">{{ teamView.totalHours }}h / {{ teamView.expectedTotalHours }}h</span>
          </div>
          <div class="tw-kpi">
            <span class="tw-kpi__label">团队均值</span>
            <span class="tw-kpi__value">
              {{ teamView.averageHours }}
              <span class="tw-kpi__unit">h</span>
            </span>
            <span class="tw-kpi__sub">{{ teamView.members.length }} 人</span>
          </div>
          <div class="tw-kpi">
            <span class="tw-kpi__label">偏低</span>
            <span class="tw-kpi__value" :class="{ 'is-danger': teamView.lowCount > 0 }">
              {{ teamView.lowCount }}
              <span class="tw-kpi__unit">人</span>
            </span>
            <span class="tw-kpi__sub">低于均值 80%</span>
          </div>
          <div class="tw-kpi">
            <span class="tw-kpi__label">加班</span>
            <span class="tw-kpi__value" :class="{ 'is-warn': teamView.highCount > 0 }">
              {{ teamView.highCount }}
              <span class="tw-kpi__unit">人</span>
            </span>
            <span class="tw-kpi__sub">超 45h</span>
          </div>
        </div>

        <div ref="teamBarRef" class="tw-bar" />

        <div v-if="teamView.lowest && teamView.highest" class="tw-footer">
          <span>
            <SvgIcon icon="mdi:arrow-down-bold-circle-outline" class="tw-footer__icon is-danger" />
            最低
            <b>{{ teamView.lowest.memberName }}</b>
            {{ teamView.lowest.hours }}h
          </span>
          <span class="tw-footer__sep">·</span>
          <span>
            <SvgIcon icon="mdi:arrow-up-bold-circle-outline" class="tw-footer__icon is-warn" />
            最高
            <b>{{ teamView.highest.memberName }}</b>
            {{ teamView.highest.hours }}h
          </span>
        </div>
      </template>
      <ElEmpty v-else description="该周无团队工时数据" :image-size="60" />
    </div>
  </WorkbenchModuleCard>
</template>

<style scoped>
/* ============ 顶部 tab + 周选择器 ============ */
.ww-tabbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--el-border-color-lighter);
}
.ww-tabs {
  flex: 1;
  min-width: 0;
}
.ww-tabs :deep(.el-tabs__header) {
  margin: 0;
}
.ww-tabs :deep(.el-tabs__nav-wrap::after) {
  display: none;
}
.ww-week-picker {
  width: 180px;
  flex-shrink: 0;
  margin-bottom: 8px;
}

/* ============ 我的工时 ============ */
.ww-headline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 16px;
  margin-bottom: 10px;
}

.ww-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
}
@media (width <= 520px) {
  .ww-grid {
    grid-template-columns: 1fr;
  }
  .ww-headline {
    grid-template-columns: 1fr;
  }
}

.ww-block {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ww-section-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--el-text-color-secondary);
  min-width: 0;
}
.ww-section-icon {
  font-size: 14px;
  color: var(--el-text-color-placeholder);
  flex-shrink: 0;
}

.ww-pie-wrap {
  position: relative;
  width: 100%;
  height: 280px;
}
.ww-pie {
  width: 100%;
  height: 100%;
}

.ww-bar {
  width: 100%;
  height: 280px;
}
.ww-bar-legend {
  display: flex;
  justify-content: center;
  gap: 16px;
  margin-top: 8px;
  font-size: 11px;
  color: var(--el-text-color-secondary);
}
.ww-bar-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.ww-bar-legend__swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

.ww-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--el-border-color-lighter);
  font-size: 13px;
}
.ww-footer b {
  font-weight: 700;
}
.ww-footer__delta {
  font-weight: 600;
}
.ww-footer__delta.is-success {
  color: var(--el-color-success);
}
.ww-footer__delta.is-danger {
  color: var(--el-color-danger);
}
.ww-footer__delta.is-muted {
  color: var(--el-text-color-secondary);
}

/* ============ 团队工时 ============ */
.tw-kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}
.tw-kpi {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  background: var(--el-fill-color-lighter);
  border-radius: 8px;
  min-width: 0;
}
.tw-kpi__label {
  font-size: 11px;
  color: var(--el-text-color-secondary);
}
.tw-kpi__value {
  font-size: 20px;
  font-weight: 700;
  color: var(--el-text-color-primary);
  line-height: 1.2;
}
.tw-kpi__value.is-danger {
  color: var(--el-color-danger);
}
.tw-kpi__value.is-warn {
  color: var(--el-color-warning);
}
.tw-kpi__unit {
  font-size: 12px;
  font-weight: 500;
  color: var(--el-text-color-secondary);
  margin-left: 2px;
}
.tw-kpi__sub {
  font-size: 11px;
  color: var(--el-text-color-placeholder);
}

.tw-bar {
  width: 100%;
  height: 240px;
}

.tw-footer {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}
.tw-footer b {
  color: var(--el-text-color-primary);
  font-weight: 600;
  margin: 0 2px;
}
.tw-footer__icon {
  vertical-align: -2px;
  margin-right: 2px;
  font-size: 13px;
}
.tw-footer__icon.is-danger {
  color: var(--el-color-danger);
}
.tw-footer__icon.is-warn {
  color: var(--el-color-warning);
}
.tw-footer__sep {
  color: var(--el-text-color-placeholder);
}

@media (width <= 520px) {
  .tw-kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
</style>
