import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../../infrastructure/database/database.service';
export interface PlaceEventOutcomeSummary {
outcomeCount: number;
alignedCount: number;
varianceCount: number;
varianceRate: number;
economicOutcomeCount: number;
economicAlignedCount: number;
economicVarianceCount: number;
economicVarianceRate: number;
confidence: 'high' | 'medium' | 'low';
}
@Injectable()
export class PlaceEventOutcomeReadService {
constructor(private readonly database: DatabaseService) {}
async summarize(organizationId: string, limit = 100): Promise<PlaceEventOutcomeSummary> {
if (typeof organizationId !== 'string' || !organizationId.trim() || !Number.isSafeInteger(limit) || limit < 1 || limit > 1000) {
throw new Error('place_event_outcome.summary_invalid');
}
const rows = await this.database.query<{status: string; economic_status: string | null; count: number}>(
`select metadata->>'status' as status, metadata->>'economicStatus' as economic_status, count(*)::int as count
from (
select metadata
from audit_events
where organization_id=$1
and event_type='place_event.recommendation.outcome_recorded'
order by occurred_at desc
limit $2
) recent_outcomes
group by metadata->>'status', metadata->>'economicStatus'`,
[organizationId.trim(), limit],
);
const alignedCount = rows.filter((row) => row.status === 'aligned').reduce((sum, row) => sum + Number(row.count), 0);
const varianceCount = rows.filter((row) => row.status === 'variance').reduce((sum, row) => sum + Number(row.count), 0);
const outcomeCount = alignedCount + varianceCount;
const economicAlignedCount = rows.filter((row) => row.economic_status === 'aligned').reduce((sum, row) => sum + Number(row.count), 0);
const economicVarianceCount = rows.filter((row) => row.economic_status === 'variance').reduce((sum, row) => sum + Number(row.count), 0);
const economicOutcomeCount = economicAlignedCount + economicVarianceCount;
return {
outcomeCount,
alignedCount,
varianceCount,
varianceRate: outcomeCount === 0 ? 0 : varianceCount / outcomeCount,
economicOutcomeCount,
economicAlignedCount,
economicVarianceCount,
economicVarianceRate: economicOutcomeCount === 0 ? 0 : economicVarianceCount / economicOutcomeCount,
confidence: outcomeCount >= 10 ? 'high' : outcomeCount >= 3 ? 'medium' : 'low',
};
}
}
