import dayjs from 'dayjs';

export type WorkbenchTodoCategory = 'task' | 'ticket' | 'personal' | 'approval';

export type WorkbenchTodoMainTab = 'all' | WorkbenchTodoCategory;

export type WorkbenchTodoDeadlineFilter = 'overdue' | 'today' | 'week' | null;

export type WorkbenchTodoPriority = 'high' | 'mid' | 'low';

export interface WorkbenchTodoItemSource {
  id: string;
  category: WorkbenchTodoCategory;
  /** 左侧分类 tag 文案；不传时按 category 默认映射 */
  categoryLabel?: string;
  /** 左侧分类 tag 色调；不传时按 category 默认映射 */
  categoryTone?: WorkbenchTodoItem['categoryTone'];
  title: string;
  /** 创建时间，ISO 字符串。列表默认按这个升序 */
  createdTime: string;
  /** 截止时间，ISO 字符串 */
  deadline: string | null;
  /** 来源（提交人/项目名/工单号） */
  source: string;
  /** 进度百分比，仅任务和我的事项使用 */
  progressRate?: number | null;
  /** 优先级，用于前端排序与高亮 */
  priority?: WorkbenchTodoPriority;
  /** 优先级原始标签（字典 label，如 P0~P3），有值才渲染角标；不做高/中/低翻译 */
  priorityLabel?: string | null;
  /** 是否逾期 */
  overdue?: boolean;
  /** 跳转路由 key（可选，未配则不跳转） */
  routeKey?: string;
  /** 任务条目携带：所属项目 ID，点击带对象上下文跳进该项目的任务导航 */
  projectId?: string;
  /** 审批业务类型 */
  approvalBizType?: 'overtime_application' | string;
  /** 审批业务 ID */
  approvalBizId?: string;
}

export interface WorkbenchTodoItem extends Omit<WorkbenchTodoItemSource, 'deadline'> {
  deadlineLabel: string;
  /** 相对截止天数：负数表示已逾期 */
  remainingDays: number | null;
  categoryLabel: string;
  categoryTone: 'sky' | 'emerald' | 'amber' | 'rose' | 'violet';
}

/** 「我参与的项目」展示项（由 Api.Project.MyParticipatedProjectItem 衍生） */
export interface WorkbenchParticipatedProjectView {
  id: string;
  name: string;
  code: string | null;
  statusName: string | null;
  statusTone: 'sky' | 'emerald' | 'amber';
  myRole: string | null;
  progress: number;
  myTaskCount: number;
  myPendingTaskCount: number;
}

const todoCategoryMeta: Record<
  WorkbenchTodoCategory,
  { label: string; tone: WorkbenchTodoItem['categoryTone']; icon: string }
> = {
  task: { label: '任务', tone: 'emerald', icon: 'mdi:checkbox-marked-circle-outline' },
  ticket: { label: '工单', tone: 'amber', icon: 'mdi:ticket-confirmation-outline' },
  personal: { label: '我的事项', tone: 'violet', icon: 'mdi:notebook-edit-outline' },
  approval: { label: '待审批', tone: 'sky', icon: 'mdi:checkbox-multiple-marked-outline' }
};

const todoPriorityWeight: Record<WorkbenchTodoPriority, number> = {
  high: 0,
  mid: 1,
  low: 2
};

/** 列表只含进行中项目；按已知状态编码上色，未知回退 sky */
function resolveParticipatedProjectTone(statusCode: string): 'sky' | 'emerald' | 'amber' {
  if (statusCode === 'active') return 'emerald';
  if (statusCode === 'paused') return 'amber';
  return 'sky';
}

function clampPercent(value: number) {
  if (!Number.isFinite(value)) return 0;
  return Math.min(100, Math.max(0, Math.round(value)));
}

function formatDeadline(value: string | null) {
  if (!value) return '不限';
  const target = dayjs(value);
  if (!target.isValid()) return '不限';

  const now = dayjs().startOf('day');
  const start = target.startOf('day');
  const days = start.diff(now, 'day');

  if (days === 0) return `今日 ${target.format('HH:mm')}`;
  if (days === 1) return `明日 ${target.format('HH:mm')}`;
  if (days === -1) return `昨日 ${target.format('HH:mm')}`;
  if (days > 0 && days <= 7) return `${days} 天后 ${target.format('MM-DD')}`;
  if (days < 0) return `逾期 ${Math.abs(days)} 天`;
  return target.format('YYYY-MM-DD');
}

function getRemainingDays(value: string | null) {
  if (!value) return null;
  const target = dayjs(value);
  if (!target.isValid()) return null;

  return target.startOf('day').diff(dayjs().startOf('day'), 'day');
}

export function buildWorkbenchTodoItems(source: readonly WorkbenchTodoItemSource[]): WorkbenchTodoItem[] {
  return [...source]
    .sort((left, right) => {
      const leftCreated = dayjs(left.createdTime).valueOf();
      const rightCreated = dayjs(right.createdTime).valueOf();
      if (leftCreated !== rightCreated) return leftCreated - rightCreated;
      const leftDeadline = left.deadline ? dayjs(left.deadline).valueOf() : Number.POSITIVE_INFINITY;
      const rightDeadline = right.deadline ? dayjs(right.deadline).valueOf() : Number.POSITIVE_INFINITY;
      return leftDeadline - rightDeadline;
    })
    .map(item => {
      const meta = todoCategoryMeta[item.category];
      return {
        ...item,
        deadlineLabel: formatDeadline(item.deadline),
        remainingDays: getRemainingDays(item.deadline),
        categoryLabel: item.categoryLabel || meta.label,
        categoryTone: item.categoryTone || meta.tone
      } satisfies WorkbenchTodoItem;
    });
}

export function filterWorkbenchTodoItemsByCategory(items: readonly WorkbenchTodoItem[], tab: WorkbenchTodoMainTab) {
  if (tab === 'all') return [...items];
  return items.filter(item => item.category === tab);
}

export function filterWorkbenchTodoItemsByDeadline(
  items: readonly WorkbenchTodoItem[],
  filter: WorkbenchTodoDeadlineFilter
) {
  if (!filter) return [...items];
  if (filter === 'overdue') return items.filter(item => isOverdue(item));
  if (filter === 'today') return items.filter(item => item.remainingDays === 0);
  // filter === 'week'：含今日，含逾期一起暴露给用户处理
  return items.filter(item => item.remainingDays !== null && item.remainingDays <= 7);
}

export function isWorkbenchTodoOverdue(item: WorkbenchTodoItem) {
  return isOverdue(item);
}

function isOverdue(item: WorkbenchTodoItem) {
  if (item.overdue) return true;
  return item.remainingDays !== null && item.remainingDays < 0;
}

export function sortWorkbenchTodoItemsByPriority(
  items: readonly WorkbenchTodoItem[],
  direction: 'asc' | 'desc' = 'desc'
) {
  const factor = direction === 'desc' ? 1 : -1;
  return [...items].sort((left, right) => {
    const leftWeight = todoPriorityWeight[left.priority ?? 'low'];
    const rightWeight = todoPriorityWeight[right.priority ?? 'low'];
    if (leftWeight !== rightWeight) return (leftWeight - rightWeight) * factor;
    return dayjs(left.createdTime).valueOf() - dayjs(right.createdTime).valueOf();
  });
}

export function buildWorkbenchParticipatedProjects(
  source: readonly Api.Project.MyParticipatedProjectItem[]
): WorkbenchParticipatedProjectView[] {
  return source.map(item => ({
    id: item.id,
    name: item.name,
    code: item.code,
    statusName: item.statusName,
    statusTone: resolveParticipatedProjectTone(item.statusCode),
    myRole: item.myRole,
    progress: clampPercent(item.progress),
    myTaskCount: item.myTaskCount,
    myPendingTaskCount: item.myPendingTaskCount
  }));
}

/** 「我负责的项目」成员负载展示项 */
export interface WorkbenchOwnedProjectMemberView {
  userId: string;
  userName: string | null;
  /** 该成员在本项目下进行中任务数 */
  activeTaskCount: number;
}

/** 「我负责的项目」展示项（由 Api.Project.MyOwnedProjectItem 衍生） */
export interface WorkbenchOwnedProjectView {
  id: string;
  name: string;
  code: string | null;
  progress: number;
  myRole: string | null;
  executionCount: number;
  taskCount: number;
  overdueCount: number;
  memberCount: number;
  /** 计划结束日期 YYYY-MM-DD，可空 */
  plannedEndDate: string | null;
  /** 距计划结束剩余天数（负=已逾期）；plannedEndDate 为空时 null */
  remainingDays: number | null;
  members: WorkbenchOwnedProjectMemberView[];
}

export function buildWorkbenchOwnedProjects(
  source: readonly Api.Project.MyOwnedProjectItem[]
): WorkbenchOwnedProjectView[] {
  return source.map(item => ({
    id: item.id,
    name: item.name,
    code: item.code,
    progress: clampPercent(item.progress),
    myRole: item.myRole,
    executionCount: item.executionCount,
    taskCount: item.taskCount,
    overdueCount: item.overdueCount,
    memberCount: item.memberCount,
    plannedEndDate: item.plannedEndDate,
    remainingDays: getRemainingDays(item.plannedEndDate),
    members: item.members.map(member => ({
      userId: member.userId,
      userName: member.userName,
      activeTaskCount: member.activeTaskCount
    }))
  }));
}

/** 工时分布行项：项目 / 我的事项 / 其他（杂项） */
export interface WorkbenchWorklogDistributionItem {
  /** 唯一 key；project 用 projectId，personal/other 用固定字面量 */
  key: string;
  label: string;
  hours: number;
  kind: 'project' | 'personal' | 'other';
  /** kind === 'project' 时携带，用于跳转项目对象上下文 */
  projectId?: string;
}

/** 周标准工时：系统无配置项，后端不返回，产品确认前端落常量 35（不是 40） */
export const WORKBENCH_WEEK_TARGET_HOURS = 35;

/** 单周工时视图（builder 衍生；接口返回周一~周日逐日工时，按周填报时仅均摊到工作日） */
export interface WorkbenchWeekWorklogView {
  weekStart: string;
  weekLabel: string;
  /** 周一~周日逐日工时（7 长度；周末单天工时保留在周末当天） */
  dailyHours: number[];
  /** 是否展示周末两列；仅当周六或周日任一天 > 0 时展示 */
  showWeekend: boolean;
  /** 图表/逐日展示实际使用的横轴标签 */
  visibleDayLabels: string[];
  /** 图表/逐日展示实际使用的逐日工时数据 */
  visibleDailyHours: number[];
  /** 本周累计 */
  totalHours: number;
  target: number;
  /** 累计 - 目标；正=领先、负=落后 */
  delta: number;
  /** 达成率，0-100 整数 */
  completionRate: number;
  distribution: WorkbenchWorklogDistributionItem[];
}

const WORKDAY_COUNT = 5;
const FULL_WEEKDAY_COUNT = 7;
const WORKDAY_LABELS = ['一', '二', '三', '四', '五'] as const;
const FULL_WEEKDAY_LABELS = ['一', '二', '三', '四', '五', '六', '日'] as const;

function roundHours(value: number) {
  return Math.round(value * 10) / 10;
}

/** 契约分布项 → 展示行项（key/label 归一，kind != project 时用固定字面量） */
function toWorklogDistributionItem(item: Api.Project.WorklogDistributionItem): WorkbenchWorklogDistributionItem {
  const isProject = item.kind === 'project' && Boolean(item.projectId);
  return {
    key: isProject ? (item.projectId as string) : item.kind,
    label: item.projectName ?? (item.kind === 'personal' ? '我的事项' : '其他'),
    hours: roundHours(item.hours),
    kind: item.kind,
    projectId: isProject ? (item.projectId as string) : undefined
  };
}

export function buildWorkbenchWeekWorklogView(source: Api.Project.MyWorklogWeekResult): WorkbenchWeekWorklogView {
  const start = dayjs(source.weekStart);
  const weekLabel = start.isValid() ? `${start.isoWeekYear()}年第${start.isoWeek()}周` : source.weekStart;

  const dailyHours = Array.from({ length: FULL_WEEKDAY_COUNT }, (_, i) => roundHours(source.dailyHours[i] ?? 0));
  const sat = Number(dailyHours[5] ?? 0);
  const sun = Number(dailyHours[6] ?? 0);
  const showWeekend = sat > 0 || sun > 0;
  const visibleDayLabels = showWeekend ? [...FULL_WEEKDAY_LABELS] : [...WORKDAY_LABELS];
  const visibleDailyHours = showWeekend ? [...dailyHours] : dailyHours.slice(0, WORKDAY_COUNT);
  const totalHours = roundHours(dailyHours.reduce((s, h) => s + h, 0));
  const target = WORKBENCH_WEEK_TARGET_HOURS;
  const delta = roundHours(totalHours - target);
  const completionRate = target > 0 ? clampPercent((totalHours / target) * 100) : 0;

  return {
    weekStart: source.weekStart,
    weekLabel,
    dailyHours,
    showWeekend,
    visibleDayLabels,
    visibleDailyHours,
    totalHours,
    target,
    delta,
    completionRate,
    distribution: source.distribution.map(toWorklogDistributionItem)
  };
}

export function getGreeting(hour: number = dayjs().hour()) {
  if (hour < 6) return '凌晨好';
  if (hour < 11) return '早上好';
  if (hour < 13) return '中午好';
  if (hour < 18) return '下午好';
  if (hour < 22) return '晚上好';
  return '夜深了';
}

// === 团队工时分布（D16 团队 tab，原 C12 teamWorklog） ===

/** 团队工时分布视图（builder 衍生） */
export interface WorkbenchTeamWorklogView {
  weekStart: string;
  weekLabel: string;
  members: Array<{
    memberId: string;
    memberName: string;
    totalHours: number;
    overtimeHours: number;
  }>;
  /** 团队总工时 */
  totalHours: number;
  /** 团队人均工时 */
  averageHours: number;
  /** 应填工时合计（人数 × WORKBENCH_WEEK_TARGET_HOURS） */
  expectedTotalHours: number;
  /** 填报率 0-100 整数（= 总工时 / 应填工时） */
  fillRate: number;
  /** 偏低人数：< 团队均值 × 0.8 */
  lowCount: number;
  /** 工时最低成员（用于底部小结） */
  lowest: { memberName: string; hours: number } | null;
  /** 工时最高成员（用于底部小结） */
  highest: { memberName: string; hours: number } | null;
}

export function buildWorkbenchTeamWorklogView(source: Api.Project.TeamWorklogWeekResult): WorkbenchTeamWorklogView {
  const start = dayjs(source.weekStart);
  const weekLabel = start.isValid() ? `${start.isoWeekYear()}年第${start.isoWeek()}周` : source.weekStart;

  // 契约：members[0] 恒为当前用户，展示加「（我）」后缀
  const members = source.members.map((member, index) => {
    const items = member.items.map(toWorklogDistributionItem);
    const totalHours = roundHours(items.reduce((sum, item) => sum + item.hours, 0));
    const overtimeHours = roundHours(member.overtimeHours ?? 0);

    return {
      memberId: member.userId,
      memberName: index === 0 ? `${member.userNickname}（我）` : member.userNickname,
      totalHours,
      overtimeHours
    };
  });

  const totalHours = roundHours(members.reduce((sum, member) => sum + member.totalHours, 0));
  const memberCount = members.length;
  const averageHours = memberCount > 0 ? roundHours(totalHours / memberCount) : 0;
  const expectedTotalHours = memberCount * WORKBENCH_WEEK_TARGET_HOURS;
  const fillRate = expectedTotalHours > 0 ? clampPercent((totalHours / expectedTotalHours) * 100) : 0;

  const lowThreshold = averageHours * 0.8;
  const lowCount = members.filter(member => member.totalHours < lowThreshold).length;

  let lowest: { memberName: string; hours: number } | null = null;
  let highest: { memberName: string; hours: number } | null = null;
  for (const member of members) {
    if (!lowest || member.totalHours < lowest.hours)
      lowest = { memberName: member.memberName, hours: member.totalHours };
    if (!highest || member.totalHours > highest.hours)
      highest = { memberName: member.memberName, hours: member.totalHours };
  }

  return {
    weekStart: source.weekStart,
    weekLabel,
    members,
    totalHours,
    averageHours,
    expectedTotalHours,
    fillRate,
    lowCount,
    lowest,
    highest
  };
}

// === 团队负载（C13 · teamLoad） ===

export type WorkbenchTeamLoadLevel = 'high' | 'mid' | 'normal';

export type WorkbenchTeamLoadItemKind = 'project' | 'personal' | 'other';

export interface WorkbenchTeamLoadItemSource {
  /** projectId 或 'personal' / 'other' */
  key: string;
  label: string;
  kind: WorkbenchTeamLoadItemKind;
  /** 该项目/我的事项下，该成员未完成的任务/事项数（含待开始/已暂停；任务按"负责人/协办人"口径，单任务多人各算 1 条） */
  count: number;
}

export interface WorkbenchTeamLoadMemberSource {
  memberId: string;
  memberName: string;
  /** 未完成数按项目 + 我的事项的拆分（合计即"未完成总数"） */
  items: WorkbenchTeamLoadItemSource[];
  /** 今天 ≤ 计划结束 ≤ 今天+3 天 且未完成（与逾期互斥） */
  dueSoon: number;
  /** 计划结束 < 今天 且未完成 */
  overdue: number;
}

export interface WorkbenchTeamLoadSource {
  members: WorkbenchTeamLoadMemberSource[];
}

export interface WorkbenchTeamLoadSegment extends WorkbenchTeamLoadItemSource {
  /** 段宽占"柱子内部"的百分比（段总和 = 100%） */
  widthPercent: number;
}

export interface WorkbenchTeamLoadMember extends Omit<WorkbenchTeamLoadMemberSource, 'items'> {
  /** items 合计（未完成总数） */
  inProgress: number;
  /** dueSoon + overdue */
  urgent: number;
  level: WorkbenchTeamLoadLevel;
  /** 项目段（去掉 count = 0） */
  segments: WorkbenchTeamLoadSegment[];
  /** 柱子总长占容器百分比（0-100），溢出时 = 100 */
  barWidthPercent: number;
  /** 溢出数量：inProgress - scaleMax（不溢出 = 0），柱子末端显示 "+N" */
  overflowExtra: number;
}

export interface WorkbenchTeamLoadView {
  /** 已按 level → inProgress desc 排序，高负载置顶 */
  members: WorkbenchTeamLoadMember[];
  /** 柱子量程上限（固定值，避免某个成员极端值把全员压扁） */
  scaleMax: number;
  highCount: number;
  midCount: number;
  /** 临期+逾期总条数（团队聚合） */
  urgentTotal: number;
}

const TEAM_LOAD_INPROGRESS_HIGH = 6;
const TEAM_LOAD_INPROGRESS_MID = 4;
const TEAM_LOAD_URGENT_HIGH = 2;
const TEAM_LOAD_URGENT_MID = 1;
/** 柱子量程上限：固定 10，确保高负载阈值 6 在 60% 位置可辨；超出走 "+N" 文字 */
const TEAM_LOAD_SCALE_MAX = 10;

function resolveTeamLoadLevel(inProgress: number, urgent: number): WorkbenchTeamLoadLevel {
  if (inProgress >= TEAM_LOAD_INPROGRESS_HIGH || urgent >= TEAM_LOAD_URGENT_HIGH) return 'high';
  if (inProgress >= TEAM_LOAD_INPROGRESS_MID || urgent >= TEAM_LOAD_URGENT_MID) return 'mid';
  return 'normal';
}

const LEVEL_RANK: Record<WorkbenchTeamLoadLevel, number> = { high: 0, mid: 1, normal: 2 };

export function buildWorkbenchTeamLoadView(source: WorkbenchTeamLoadSource): WorkbenchTeamLoadView {
  const scaleMax = TEAM_LOAD_SCALE_MAX;

  const enriched: WorkbenchTeamLoadMember[] = source.members.map(m => {
    const inProgress = m.items.reduce((s, it) => s + it.count, 0);
    const urgent = m.dueSoon + m.overdue;
    const barWidthPercent = scaleMax > 0 ? Math.min(100, (inProgress / scaleMax) * 100) : 0;
    const overflowExtra = Math.max(0, inProgress - scaleMax);
    // 段宽永远相对柱子内部按 count/inProgress 算（段总和 = 100%）
    // 柱子总长靠 barWidthPercent 控制；不溢出时柱子未顶满，溢出时柱子顶满 + 末端 +N
    const segments: WorkbenchTeamLoadSegment[] = m.items
      .filter(it => it.count > 0)
      .map(it => ({
        ...it,
        widthPercent: inProgress > 0 ? (it.count / inProgress) * 100 : 0
      }));
    return {
      memberId: m.memberId,
      memberName: m.memberName,
      dueSoon: m.dueSoon,
      overdue: m.overdue,
      inProgress,
      urgent,
      level: resolveTeamLoadLevel(inProgress, urgent),
      segments,
      barWidthPercent,
      overflowExtra
    };
  });

  enriched.sort((a, b) => {
    if (LEVEL_RANK[a.level] !== LEVEL_RANK[b.level]) return LEVEL_RANK[a.level] - LEVEL_RANK[b.level];
    if (a.inProgress !== b.inProgress) return b.inProgress - a.inProgress;
    return b.urgent - a.urgent;
  });

  const highCount = enriched.filter(m => m.level === 'high').length;
  const midCount = enriched.filter(m => m.level === 'mid').length;
  const urgentTotal = enriched.reduce((s, m) => s + m.urgent, 0);

  return {
    members: enriched,
    scaleMax,
    highCount,
    midCount,
    urgentTotal
  };
}

export type WorkbenchHealthLevel = 'green' | 'yellow' | 'red';

export interface WorkbenchProjectHealthCardSource {
  projectId: string;
  projectName: string;
  code: string;
  health: WorkbenchHealthLevel;
  riskCount: number;
  overdueTasks: number;
  backlogRequirements: number;
}

export interface WorkbenchProjectHealthCard extends WorkbenchProjectHealthCardSource {
  healthLabel: string;
}

export function buildWorkbenchProjectHealthCards(
  source: readonly WorkbenchProjectHealthCardSource[]
): WorkbenchProjectHealthCard[] {
  const labelMap: Record<WorkbenchHealthLevel, string> = { green: '健康', yellow: '关注', red: '风险' };
  return source.map(s => ({ ...s, healthLabel: labelMap[s.health] }));
}

/**
 * 前端兜底过滤：剔除已完成 / 已取消 / 进度满 100 的执行（默认不在工作台呈现）。
 * 后端接口已按此口径过滤，此处为双保险；泛型保证接口返回类型可复用。
 */
export function buildWorkbenchMyExecutionItems<T extends { statusCode: string; progressRate: number }>(
  source: readonly T[]
): T[] {
  return source.filter(item => {
    if (item.statusCode === 'completed' || item.statusCode === 'cancelled') return false;
    if (item.progressRate >= 100) return false;
    return true;
  });
}
