import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, isDevMode } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Observable, Subject, Subscription, debounceTime } from 'rxjs';
import { ProjectService } from '../../../services/project.service';
import { Task, ProjectStage } from '../../../models/project.model';
import { Router } from '@angular/router';

interface CalendarDay {
  date: Date;
  currentMonth: boolean;
  tasks: Task[];
}

@Component({
  selector: 'app-workload-calendar',
  standalone: true,
  imports: [CommonModule, FormsModule],
  templateUrl: './workload-calendar.html',
  styleUrls: ['./workload-calendar.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class WorkloadCalendarComponent implements OnInit, OnDestroy {
  view: 'day' | 'week' | 'month' = 'month';
  selectedDate: Date = new Date();
  today: Date = new Date();
  selectedDesigner: string = 'all';
  designers: string[] = [];
  tasks: Task[] = [];
  monthDays: CalendarDay[] = [];
  showOverdueOnly: boolean = false;
  expandedDays = new Set<string>();
  designerStatuses: { name: string; label: string; cls: string; tasksCount: number; overdue: number }[] = [];
  weekDays: CalendarDay[] = [];
  // 新增：快捷范围与阶段筛选
  quickRange: 'all' | 'today' | '3d' | '7d' = 'all';
  selectedPhase: 'all' | '待分配' | '需求方案' | '执行' | '收尾验收' | '归档' = 'all';
  phases: Array<'待分配' | '需求方案' | '执行' | '收尾验收' | '归档'> = ['待分配', '需求方案', '执行', '收尾验收', '归档'];
  // 缓存：模板直接使用，避免频繁函数调用
  dayTasks: Task[] = [];
  monthLabel: string = '';
  // 记忆化：周期筛选缓存
  private tasksVersion = 0;
  private memoSignature = '';
  private memoPeriodTasks: Task[] = [];
  private monthTaskMap: Map<string, Task[]> = new Map();
  private monthTaskMapKey: string | null = null; // 记录缓存对应的年月（YYYY-MM）
  private recompute$ = new Subject<void>();
  private recomputeSub?: Subscription;
  private tasksSub?: Subscription;

  constructor(private projectService: ProjectService, private router: Router) {}

  ngOnInit(): void {
    // 恢复上次的视图状态
    try {
      const savedRaw = localStorage.getItem('workloadCalendarState');
      if (savedRaw) {
        const saved = JSON.parse(savedRaw);
        if (saved.view) this.view = saved.view;
        if (saved.selectedDesigner) this.selectedDesigner = saved.selectedDesigner;
        if (typeof saved.showOverdueOnly === 'boolean') this.showOverdueOnly = saved.showOverdueOnly;
        if (saved.selectedDate) this.selectedDate = new Date(saved.selectedDate);
        if (saved.quickRange) this.quickRange = saved.quickRange;
        if (saved.selectedPhase) this.selectedPhase = saved.selectedPhase;
      }
    } catch {}

    // 初始化变更去抖订阅：合并快速连续变更并统一重算
    this.recomputeSub = this.recompute$.pipe(debounceTime(50)).subscribe(() => this.recomputeAll());

    // 开发模式：允许通过 localStorage.mockTasks 注入大数据量以进行性能压测
    const mockSizeRaw = isDevMode() ? localStorage.getItem('mockTasks') : null;
    const mockSize = mockSizeRaw ? Number(mockSizeRaw) : NaN;
    const tasks$ : Observable<Task[]> = isDevMode() && Number.isFinite(mockSize) && mockSize > 0
      ? (console.info('[WorkloadCalendar] Using mock tasks for benchmarking:', mockSize), this.projectService.getTasks(mockSize))
      : this.projectService.getTasks();

    this.tasksSub = tasks$.subscribe((tasks: Task[]) => {
      // 仅将有截止日期的任务纳入排期，并规范化 deadline 类型
      this.tasks = (tasks || [])
        .filter((t: Task) => !!t.deadline)
        .map((t: Task) => ({ ...t, deadline: new Date(t.deadline) } as Task));
      this.tasksVersion++;
      this.designers = Array.from(new Set(this.tasks.map(t => t.assignee))).filter(Boolean).sort();
      // 懒构建：仅为当前视图构建相应数据
      if (this.view === 'month') this.buildMonthDays();
      else if (this.view === 'week') this.buildWeekDays();
      this.computeDesignerStatuses();
      // 初始化缓存
      this.monthLabel = this.formatMonthYear(this.selectedDate);
      this.dayTasks = this.getTasksForDate(this.selectedDate);
    });
  }

  ngOnDestroy(): void {
    this.recomputeSub?.unsubscribe();
    this.tasksSub?.unsubscribe();
  }

  private computeDesignerStatuses(): void {
    if (isDevMode()) console.time('computeDesignerStatuses');
    const periodTasks = this.getPeriodFilteredTasks();
    const agg = new Map<string, { count: number; overdue: number }>();
    for (const t of periodTasks) {
      const name = t.assignee || '未分配';
      const cur = agg.get(name) || { count: 0, overdue: 0 };
      cur.count += 1;
      if (t.isOverdue) cur.overdue += 1;
      agg.set(name, cur);
    }
    this.designerStatuses = this.designers.map(name => {
      const a = agg.get(name) || { count: 0, overdue: 0 };
      let label = '正常', cls = 'normal';
      if (a.overdue > 0) { label = '异常'; cls = 'abnormal'; }
      else if (a.count === 0) { label = '空闲'; cls = 'idle'; }
      else if ((this.view === 'week' && a.count >= 6) || (this.view === 'month' && a.count >= 15) || (this.view === 'day' && a.count >= 3)) { label = '繁忙'; cls = 'busy'; }
      return { name, label, cls, tasksCount: a.count, overdue: a.overdue };
    });
    if (isDevMode()) console.timeEnd('computeDesignerStatuses');
  }

  private getPeriodFilteredTasks(): Task[] {
    const tasks = this.tasks.filter(t => (!this.showOverdueOnly || t.isOverdue))
      .filter(t => this.matchesQuickRange(t))
      .filter(t => this.matchesPhase(t));
    const d = this.selectedDate;
    if (this.view === 'day') {
      return tasks.filter(t => this.isSameDay(t.deadline, d));
    }
    if (this.view === 'week') {
      const day = d.getDay() || 7;
      const start = new Date(d); start.setDate(d.getDate() - day + 1);
      const end = new Date(start); end.setDate(start.getDate() + 6);
      return tasks.filter(t => t.deadline >= start && t.deadline <= end);
    }
    const start = new Date(d.getFullYear(), d.getMonth(), 1);
    const end = new Date(d.getFullYear(), d.getMonth() + 1, 0);
    return tasks.filter(t => t.deadline >= start && t.deadline <= end);
  }

  // 计算设计师在当前视图周期下的工作状态
  getDesignerStatus(name: string): { label: string; cls: string; tasksCount: number; overdue: number } {
    // 兼容旧方法：直接从一次聚合的结果中取数
    const all = this.getPeriodFilteredTasks().filter(t => !name || t.assignee === name);
    const overdue = all.filter(t => t.isOverdue).length;
    const count = all.length;
    let label = '正常', cls = 'normal';
    if (overdue > 0) { label = '异常'; cls = 'abnormal'; }
    else if (count === 0) { label = '空闲'; cls = 'idle'; }
    else if ((this.view === 'week' && count >= 6) || (this.view === 'month' && count >= 15) || (this.view === 'day' && count >= 3)) { label = '繁忙'; cls = 'busy'; }
    return { label, cls, tasksCount: count, overdue };
  }

  private getPeriodDateRangeTasks(name?: string): Task[] {
    // 保留方法签名用于兼容，但内部委托至一次性筛选结果
    const all = this.getPeriodFilteredTasks();
    return all.filter(t => !name || t.assignee === name);
  }
  private saveState(): void {
    try {
      localStorage.setItem('workloadCalendarState', JSON.stringify({
        view: this.view,
        selectedDesigner: this.selectedDesigner,
        showOverdueOnly: this.showOverdueOnly,
        selectedDate: this.selectedDate,
        quickRange: this.quickRange,
        selectedPhase: this.selectedPhase
      }));
    } catch {}
  }

  private priorityRank(p: any): number {
    const r: Record<string, number> = { high: 3, medium: 2, low: 1 };
    const key = typeof p === 'string' ? p.toLowerCase() : String(p);
    return r[key] ?? 0;
  }

  switchView(v: 'day' | 'week' | 'month'): void {
    this.view = v;
    this.scheduleRecompute();
  }

  navigateDate(direction: 'prev' | 'next'): void {
    const d = new Date(this.selectedDate);
    if (this.view === 'day') {
      d.setDate(d.getDate() + (direction === 'prev' ? -1 : 1));
    } else if (this.view === 'week') {
      d.setDate(d.getDate() + (direction === 'prev' ? -7 : 7));
    } else {
      d.setMonth(d.getMonth() + (direction === 'prev' ? -1 : 1));
    }
    this.selectedDate = d;
    this.scheduleRecompute();
  }

  setToday(): void {
    this.selectedDate = new Date();
    this.today = new Date();
    this.scheduleRecompute();
  }

  isSameDay(a: Date, b: Date): boolean {
    return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
  }

  public isWeekend(d: Date): boolean {
    const day = d.getDay();
    return day === 0 || day === 6;
  }

  private matchesDesigner(t: Task): boolean {
    return this.selectedDesigner === 'all' || t.assignee === this.selectedDesigner;
  }

  // 新增：跳转到项目详情
  navigateToProject(t: Task, ev?: Event): void {
    if (ev) { ev.stopPropagation(); ev.preventDefault?.(); }
    if (!t || !t.projectId) return;
    // 复用设计师端项目详情页面（通过 URL 上下文赋予组长审核权限）
    this.router.navigate(['/team-leader/project-detail', t.projectId]);
  }

  // 新增：按设计师快速筛选（保持当前日期与视图）
  filterByDesigner(name: string, ev?: Event): void {
    if (ev) { ev.stopPropagation(); ev.preventDefault?.(); }
    if (!name) return;
    this.selectedDesigner = name;
    this.scheduleRecompute();
  }

  onDesignerChange(): void {
    this.scheduleRecompute();
  }

  onOverdueOnlyChange(): void {
    this.scheduleRecompute();
  }
  // 新增：快捷范围选择
  onQuickRangeSelect(r: 'all' | 'today' | '3d' | '7d'): void {
    this.quickRange = r;
    this.scheduleRecompute();
  }
  // 新增：阶段筛选变更
  onPhaseChange(): void {
    this.scheduleRecompute();
  }

  private scheduleRecompute(): void {
    this.recompute$.next();
  }

  // 统一重算入口：根据当前视图与筛选项重建展示数据与统计
  private recomputeAll(): void {
    // 月份标签
    this.monthLabel = this.formatMonthYear(this.selectedDate);

    if (this.view === 'month') {
      this.buildMonthDays();
      // 同步当天任务（供右侧面板或日视图快速切换复用）
      this.dayTasks = this.getTasksForDate(this.selectedDate);
    } else if (this.view === 'week') {
      this.buildWeekDays();
      this.dayTasks = this.getTasksForDate(this.selectedDate);
    } else { // day
      this.dayTasks = this.getTasksForDate(this.selectedDate);
    }

    // 计算设计师状态面板
    this.computeDesignerStatuses();
    // 持久化状态
    this.saveState();
  }

  // 新增：阶段归并规则（标准化为5大阶段）
  private stageToPhase(s: ProjectStage, isCompleted = false): '待分配' | '需求方案' | '执行' | '收尾验收' | '归档' {
    switch (s) {
      case '订单分配':
        return '待分配';
      case '需求沟通':
      case '方案确认':
        return '需求方案';
      case '建模':
      case '软装':
      case '渲染':
        return '执行';
      case '尾款结算':
      case '客户评价':
      case '投诉处理':
        return '收尾验收';
      default:
        return isCompleted ? '归档' : '执行';
    }
  }
  // 新增：阶段与快捷范围匹配
  private matchesPhase(t: Task): boolean {
    if (this.selectedPhase === 'all') return true;
    const phase = this.stageToPhase(t.stage, t.isCompleted);
    return phase === this.selectedPhase;
  }
  private startOfDay(d: Date): Date { const x = new Date(d); x.setHours(0,0,0,0); return x; }
  private daysUntil(d: Date): number { const t0 = this.startOfDay(new Date()); const t1 = this.startOfDay(d); return Math.round((t1.getTime() - t0.getTime()) / 86400000); }
  isDueSoon(date: Date): boolean { if (!date) return false; const diff = this.daysUntil(date); return diff >= 0 && diff <= 2; }
  private matchesQuickRange(t: Task): boolean {
    if (this.quickRange === 'all') return true;
    if (this.quickRange === 'today') return this.isSameDay(t.deadline, this.today);
    const diff = this.daysUntil(t.deadline);
    if (this.quickRange === '3d') return diff >= 0 && diff <= 2;
    if (this.quickRange === '7d') return diff >= 0 && diff <= 6;
    return true;
  }

  // 统一入口：按指定日期获取任务（已包含设计师/逾期/快捷范围/阶段筛选），并进行稳定排序
  private getTasksForDate(d: Date): Task[] {
    if (!d) return [];
    const key = this.toKey(d);
    const monthKey = `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}`;

    // 若月度缓存与日期同月，直接读取分组结果（已预排序）
    if (this.monthTaskMapKey === monthKey && this.monthTaskMap.size) {
      return this.monthTaskMap.get(key) || [];
    }

    // 否则即时计算（用于周/日视图或缓存未命中场景）
    const list = this.tasks
      .filter(t => this.matchesDesigner(t))
      .filter(t => (!this.showOverdueOnly || t.isOverdue))
      .filter(t => this.matchesQuickRange(t))
      .filter(t => this.matchesPhase(t))
      .filter(t => this.isSameDay(t.deadline, d));

    // 稳定排序：逾期优先 > 优先级高 > 截止时间早
    return list.sort((a, b) =>
      Number(b.isOverdue) - Number(a.isOverdue) ||
      this.priorityRank(b.priority) - this.priorityRank(a.priority) ||
      (a.deadline as any) - (b.deadline as any)
    );
  }

  getWeekDays(): CalendarDay[] {
    const base = new Date(this.selectedDate);
    const day = base.getDay() || 7; // 周日归为7
    const start = new Date(base);
    start.setDate(base.getDate() - day + 1); // 周一作为一周的第一天
    const days: CalendarDay[] = [];
    for (let i = 0; i < 7; i++) {
      const d = new Date(start);
      d.setDate(start.getDate() + i);
      days.push({ date: d, currentMonth: true, tasks: this.getTasksForDate(d) });
    }
    return days;
  }

  buildWeekDays(): void {
    if (isDevMode()) console.time('buildWeekDays');
    const base = new Date(this.selectedDate);
    const day = base.getDay() || 7; // 周日归为7
    const start = new Date(base);
    start.setDate(base.getDate() - day + 1); // 周一作为一周的第一天
    const days: CalendarDay[] = [];
    for (let i = 0; i < 7; i++) {
      const d = new Date(start);
      d.setDate(start.getDate() + i);
      days.push({ date: d, currentMonth: true, tasks: this.getTasksForDate(d) });
    }
    this.weekDays = days;
    if (isDevMode()) console.timeEnd('buildWeekDays');
  }

  getDayTasks(): Task[] {
    // 移除重复排序：getTasksForDate 已经排好序
    return this.getTasksForDate(this.selectedDate);
  }

  getPeriodTasks(): Task[] {
    if (this.view === 'day') return this.getDayTasks();
    if (this.view === 'week') {
      return this.weekDays.flatMap(d => d.tasks);
    }
    return this.monthDays.flatMap(d => d.tasks);
  }

  formatMonthYear(d: Date = this.selectedDate): string {
    return `${d.getFullYear()}年${(d.getMonth() + 1).toString().padStart(2, '0')}月`;
  }

  formatDateLabel(d: Date): string {
    return `${d.getMonth() + 1}/${d.getDate()}`;
  }

  private toKey(d: Date): string {
    return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
  }
  isExpanded(d: Date): boolean { return this.expandedDays.has(this.toKey(d)); }
  toggleExpand(d: Date, ev?: MouseEvent): void {
    if (ev) ev.stopPropagation();
    const k = this.toKey(d);
    if (this.expandedDays.has(k)) this.expandedDays.delete(k); else this.expandedDays.add(k);
  }

  selectDate(d: Date): void {
    this.selectedDate = new Date(d);
    this.view = 'day';
    this.scheduleRecompute();
  }

  buildMonthDays(): void {
    if (isDevMode()) console.time('buildMonthDays');
    const year = this.selectedDate.getFullYear();
    const month = this.selectedDate.getMonth();
    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    // 以周一为一周第一天的偏移（周一=0，周日=6）
    const firstWeekday = (firstDay.getDay() || 7) - 1;
    const days: CalendarDay[] = [];

    // 预过滤当月范围+筛选条件（设计师/仅看超期/快捷范围/阶段），并一次性按日期分组
    const monthStart = new Date(year, month, 1);
    const monthEnd = new Date(year, month + 1, 0);
    const grouped = new Map<string, Task[]>();
    const base = this.tasks.filter(t =>
      this.matchesDesigner(t) && (!this.showOverdueOnly || t.isOverdue) &&
      this.matchesQuickRange(t) && this.matchesPhase(t) &&
      t.deadline >= monthStart && t.deadline <= monthEnd
    );
    for (const t of base) {
      const k = this.toKey(t.deadline);
      const arr = grouped.get(k) || [];
      arr.push(t);
      grouped.set(k, arr);
    }
    // 统一在分组阶段做排序，避免每格重复排序
    for (const [k, arr] of grouped) {
      arr.sort((a, b) =>
        Number(b.isOverdue) - Number(a.isOverdue) ||
        this.priorityRank(b.priority) - this.priorityRank(a.priority) ||
        (a.deadline as any) - (b.deadline as any)
      );
      grouped.set(k, arr);
    }

    // 上月填充
    for (let i = firstWeekday; i > 0; i--) {
      const d = new Date(year, month, 1 - i);
      days.push({ date: d, currentMonth: false, tasks: [] });
    }
    // 当月
    for (let i = 1; i <= lastDay.getDate(); i++) {
      const d = new Date(year, month, i);
      const key = this.toKey(d);
      const tasks = grouped.get(key) || [];
      days.push({ date: d, currentMonth: true, tasks });
    }
    // 下月填充至42格
    while (days.length < 42) {
      const last = days[days.length - 1].date;
      const next = new Date(last);
      next.setDate(last.getDate() + 1);
      days.push({ date: next, currentMonth: false, tasks: [] });
    }

    this.monthDays = days;
    // 同步月度任务映射缓存
    this.monthTaskMap = grouped;
    this.monthTaskMapKey = `${year}-${(month + 1).toString().padStart(2, '0')}`;
    if (isDevMode()) console.timeEnd('buildMonthDays');
  }

  // 计算设计师在当前视图周期下的工作状态
  getDesignerStatusLegacy(name: string): { label: string; cls: string; tasksCount: number; overdue: number } {
    const periodTasks = this.getPeriodDateRangeTasksLegacy(name);
    const overdue = periodTasks.filter(t => t.isOverdue).length;
    const count = periodTasks.length;
    let label = '正常', cls = 'normal';
    if (overdue > 0) { label = '异常'; cls = 'abnormal'; }
    else if (count === 0) { label = '空闲'; cls = 'idle'; }
    else if ((this.view === 'week' && count >= 6) || (this.view === 'month' && count >= 15) || (this.view === 'day' && count >= 3)) { label = '繁忙'; cls = 'busy'; }
    return { label, cls, tasksCount: count, overdue };
  }

  private getPeriodDateRangeTasksLegacy(name?: string): Task[] {
    const tasks = this.tasks.filter(t => (!name || t.assignee === name) && (!this.showOverdueOnly || t.isOverdue));
    const d = new Date(this.selectedDate);
    if (this.view === 'day') {
      return tasks.filter(t => this.isSameDay(t.deadline, d));
    }
    if (this.view === 'week') {
      const day = d.getDay() || 7;
      const start = new Date(d); start.setDate(d.getDate() - day + 1);
      const end = new Date(start); end.setDate(start.getDate() + 6);
      return tasks.filter(t => t.deadline >= start && t.deadline <= end);
    }
    const start = new Date(d.getFullYear(), d.getMonth(), 1);
    const end = new Date(d.getFullYear(), d.getMonth() + 1, 0);
    return tasks.filter(t => t.deadline >= start && t.deadline <= end);
  }
}