import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserService, type PublicUser } from '../user/user.service';
import { Project } from '../project/entities/project.entity';
import { Activity, type ActivityType } from './entities/activity.entity';

// 활동 응답(원시) — 표시 문구/아이콘/톤은 프론트가 type+payload 로 조립
export interface ActivityResponse {
  id: string;
  type: ActivityType;
  actor: PublicUser | null;
  taskSeq: number | null;
  payload: Record<string, unknown>;
  createdAt: string;
}

// 활동 적재 파라미터
export interface RecordActivityParams {
  projectId: string; // Project uuid
  actorId: string | null;
  type: ActivityType;
  payload?: Record<string, unknown>;
  taskSeq?: number | null;
}

// 활동 피드 비즈니스 로직 — 다른 도메인 서비스가 record() 로 이벤트를 적재하고,
// 프로젝트/업무 단위로 읽어간다. 적재는 베스트 에포트(실패해도 본 기능을 막지 않음).
@Injectable()
export class ActivityService {
  private readonly logger = new Logger(ActivityService.name);

  constructor(
    @InjectRepository(Activity)
    private readonly activityRepo: Repository<Activity>,
  ) {}

  // 활동 1건 적재 — 실패해도 호출부 흐름을 깨지 않도록 내부에서 흡수
  async record(params: RecordActivityParams): Promise<void> {
    try {
      const activity = this.activityRepo.create({
        project: { id: params.projectId } as Project,
        actor: params.actorId ? { id: params.actorId } : null,
        type: params.type,
        payload: params.payload ?? {},
        taskSeq: params.taskSeq ?? null,
      });
      await this.activityRepo.save(activity);
    } catch (err) {
      this.logger.error(
        `활동 적재 실패: ${params.type}`,
        err instanceof Error ? err.stack : String(err),
      );
    }
  }

  // 프로젝트 활동 피드 — projectId(uuid)로 조회(최신순, 최대 200건). 날짜 그룹핑은 프론트.
  async listForProject(projectId: string): Promise<ActivityResponse[]> {
    const rows = await this.activityRepo.find({
      where: { project: { id: projectId } },
      relations: ['actor'],
      order: { createdAt: 'DESC' },
      take: 200,
    });
    return rows.map((a) => this.toResponse(a));
  }

  // 업무 활동 — projectId(uuid) + 업무 순번(seq) 기준(최신순). 업무 상세 활동 탭용.
  async listForTask(
    projectId: string,
    taskSeq: number,
  ): Promise<ActivityResponse[]> {
    const rows = await this.activityRepo.find({
      where: { project: { id: projectId }, taskSeq },
      relations: ['actor'],
      order: { createdAt: 'DESC' },
    });
    return rows.map((a) => this.toResponse(a));
  }

  // 엔티티 → 응답 매핑
  private toResponse(a: Activity): ActivityResponse {
    return {
      id: a.id,
      type: a.type,
      actor: a.actor ? UserService.toPublic(a.actor) : null,
      taskSeq: a.taskSeq,
      payload: a.payload ?? {},
      createdAt: a.createdAt.toISOString(),
    };
  }
}
