import {
  ConflictException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
import type {
  ReferenceValueCreate,
  ReferenceValueDto,
  ReferenceValuesResponse,
  ReferenceValueUpdate,
} from '@siop/shared';
import { PrismaService } from '../prisma/prisma.service';

const usageInclude = {
  _count: {
    select: {
      doorStates: true,
      cabinPositions: true,
      anomalies: true,
      externalCauses: true,
      actionsTaken: true,
      componentsConcerned: true,
    },
  },
} satisfies Prisma.ReferenceValueInclude;

type Row = Prisma.ReferenceValueGetPayload<{ include: typeof usageInclude }>;

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

  async list(): Promise<ReferenceValuesResponse> {
    const rows = await this.prisma.referenceValue.findMany({
      include: usageInclude,
      orderBy: [{ field: 'asc' }, { label: 'asc' }],
    });
    return { referenceValues: rows.map((r) => this.toDto(r)) };
  }

  async create(dto: ReferenceValueCreate): Promise<ReferenceValueDto> {
    try {
      const created = await this.prisma.referenceValue.create({
        data: dto,
        include: usageInclude,
      });
      return this.toDto(created);
    } catch (e) {
      if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
        throw new ConflictException('Ce libellé existe déjà pour ce champ');
      }
      throw e;
    }
  }

  /** Renommage / (dés)activation — jamais de suppression (même règle que Category). */
  async update(id: string, dto: ReferenceValueUpdate): Promise<ReferenceValueDto> {
    try {
      const updated = await this.prisma.referenceValue.update({
        where: { id },
        data: dto,
        include: usageInclude,
      });
      return this.toDto(updated);
    } catch (e) {
      if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2025') {
        throw new NotFoundException('Valeur inconnue');
      }
      if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
        throw new ConflictException('Ce libellé existe déjà pour ce champ');
      }
      throw e;
    }
  }

  private toDto(row: Row): ReferenceValueDto {
    const c = row._count;
    return {
      id: row.id,
      field: row.field,
      label: row.label,
      isActive: row.isActive,
      usageCount:
        c.doorStates +
        c.cabinPositions +
        c.anomalies +
        c.externalCauses +
        c.actionsTaken +
        c.componentsConcerned,
    };
  }
}
