import { Provide } from '@midwayjs/core';
import { BaseService } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { In, Repository } from 'typeorm';
import { ProjectTimeLogEntity } from '../entity/time_log';
import { ProjectTaskEntity } from '../entity/task';

/**
 * 工时记录服务
 */
@Provide()
export class ProjectTimeLogService extends BaseService {
  @InjectEntityModel(ProjectTimeLogEntity)
  projectTimeLogEntity: Repository<ProjectTimeLogEntity>;

  @InjectEntityModel(ProjectTaskEntity)
  projectTaskEntity: Repository<ProjectTaskEntity>;

  private affectedTaskIds = new Set<number>();

  private normalizeIds(ids: any): number[] {
    if (Array.isArray(ids)) {
      return ids.map(id => Number(id)).filter(Boolean);
    }
    if (typeof ids === 'string') {
      return ids
        .split(',')
        .map(id => Number(id))
        .filter(Boolean);
    }
    const id = Number(ids);
    return id ? [id] : [];
  }

  async modifyBefore(data: any, type: 'delete' | 'update' | 'add') {
    this.affectedTaskIds = new Set<number>();

    if (type === 'delete') {
      const ids = this.normalizeIds(data);
      if (ids.length === 0) return;

      const logs = await this.projectTimeLogEntity.findBy({ id: In(ids) });
      for (const log of logs) {
        this.affectedTaskIds.add(log.taskId);
      }
      return;
    }

    if (data.taskId) {
      this.affectedTaskIds.add(Number(data.taskId));
    }

    if (type === 'add') {
      data.userId = data.userId || this.baseCtx?.admin?.userId;
      data.userName = data.userName || this.baseCtx?.admin?.username || '当前用户';
    }
  }

  async modifyAfter(data: any, type: 'delete' | 'update' | 'add') {
    if (type !== 'delete' && data.taskId) {
      this.affectedTaskIds.add(Number(data.taskId));
    }

    for (const taskId of this.affectedTaskIds) {
      await this.recalcTaskHours(taskId);
    }
  }

  private async recalcTaskHours(taskId: number) {
    const result = await this.projectTimeLogEntity
      .createQueryBuilder('tl')
      .select('SUM(tl.hours)', 'total')
      .where('tl.taskId = :taskId', { taskId })
      .getRawOne();
    const actualHours = Number(result?.total) || 0;
    await this.projectTaskEntity.update(taskId, { actualHours });
  }
}
