import { Injectable } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { DatabaseService } from '../../../infrastructure/database/database.service';
import { DomainConflictError } from '../../../common/errors/domain-conflict.error';
import { OutboxService } from '../../../infrastructure/outbox/outbox.service';
import {
assertIncidentAssignInput,
assertIncidentCreateInput,
assertIncidentResolveInput,
} from './incident-input-validation';
@Injectable()
export class IncidentService {
constructor(
private readonly database:DatabaseService,
private readonly outbox:OutboxService,
) {}
async create(input:unknown) {
assertIncidentCreateInput(input);
const id=randomUUID();
await this.database.query(
`insert into incidents(
id,organization_id,location_id,incident_type,severity,status,
title,description,occurred_at,reported_by_employee_id,
related_entity_type,related_entity_id
) values($1,$2,$3,$4,$5,'open',$6,$7,$8,$9,$10,$11)`,
[id,input.organizationId,input.locationId,input.incidentType,input.severity,input.title,input.description,input.occurredAt,input.reportedByEmployeeId??null,input.relatedEntityType??null,input.relatedEntityId??null],
);
if(input.incidentType==='allergen' || input.severity==='critical') {
await this.outbox.append({
organizationId:input.organizationId,
aggregateType:'Incident',
aggregateId:id,
eventType:'CriticalIncidentReported',
payload:{ incidentId:id,incidentType:input.incidentType,severity:input.severity },
});
}
return {id,status:'open'};
}
async assign(input:unknown) {
assertIncidentAssignInput(input);
const rows=await this.database.query<any>(
`update incidents
set status='investigating',assigned_to_employee_id=$1,version=version+1
where id=$2 and organization_id=$3 and location_id=$4 and status='open'
returning id,status`,
[input.employeeId,input.incidentId,input.organizationId,input.locationId],
);
if(!rows[0]) throw new DomainConflictError('incidents.assign_invalid');
return rows[0];
}
async resolve(input:unknown) {
assertIncidentResolveInput(input);
const rows=await this.database.query<any>(
`update incidents
set status='resolved',resolution=$1,resolved_at=now(),version=version+1
where id=$2 and organization_id=$3 and location_id=$4 and status in ('open','investigating')
returning id,status`,
[input.resolution,input.incidentId,input.organizationId,input.locationId],
);
if(!rows[0]) throw new DomainConflictError('incidents.resolve_invalid');
return rows[0];
}
}
