import {
  ConflictException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
import type { Team, TeamCreate, TeamsResponse, TeamUpdate } from '@siop/shared';
import { PrismaService } from '../prisma/prisma.service';

const teamInclude = {
  members: { include: { role: true }, orderBy: { displayName: 'asc' } },
} satisfies Prisma.TeamInclude;

type TeamRow = Prisma.TeamGetPayload<{ include: typeof teamInclude }>;

@Injectable()
export class TeamsService {
  constructor(private readonly prisma: PrismaService) {}

  async list(): Promise<TeamsResponse> {
    const rows = await this.prisma.team.findMany({
      include: teamInclude,
      orderBy: { name: 'asc' },
    });
    return { teams: rows.map((t) => this.toDto(t)) };
  }

  async create(dto: TeamCreate): Promise<Team> {
    try {
      const created = await this.prisma.team.create({
        data: {
          name: dto.name,
          description: dto.description,
          members: dto.memberIds?.length
            ? { connect: dto.memberIds.map((id) => ({ id })) }
            : undefined,
        },
        include: teamInclude,
      });
      return this.toDto(created);
    } catch (e) {
      if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
        throw new ConflictException('Ce nom d’équipe existe déjà');
      }
      throw e;
    }
  }

  async update(id: string, dto: TeamUpdate): Promise<Team> {
    try {
      const updated = await this.prisma.team.update({
        where: { id },
        data: {
          name: dto.name,
          description: dto.description,
          members: dto.memberIds
            ? { set: dto.memberIds.map((memberId) => ({ id: memberId })) }
            : undefined,
        },
        include: teamInclude,
      });
      return this.toDto(updated);
    } catch (e) {
      if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2025') {
        throw new NotFoundException('Équipe inconnue');
      }
      if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
        throw new ConflictException('Ce nom d’équipe existe déjà');
      }
      throw e;
    }
  }

  private toDto(row: TeamRow): Team {
    return {
      id: row.id,
      name: row.name,
      description: row.description,
      members: row.members.map((m) => ({
        id: m.id,
        displayName: m.displayName,
        roleName: m.role.name,
        initials: m.displayName
          .split(/\s+/)
          .filter(Boolean)
          .slice(0, 2)
          .map((w) => w[0]!.toUpperCase())
          .join(''),
      })),
    };
  }
}
