/**
 * AwardRecognitionUseCase — spec 097, FR-30 / NFR-11.
 *
 * On a PR merge event, this use case:
 *   1. Idempotently inserts a `RecognitionEvent` keyed by
 *      (contributorId, kind, prNumber). The repository enforces this via
 *      the schema-level UNIQUE constraint plus an INSERT … ON CONFLICT
 *      DO NOTHING upsert.
 *   2. When (and only when) a row was actually inserted, updates the
 *      contributor's prCount + lastContributionAt + level (if a ladder
 *      threshold was crossed) and appends to `.all-contributorsrc` via
 *      `IAllContributorsWriter`.
 *
 * Reprocessing the same `(contributorId, kind, prNumber)` triple is a
 * complete no-op: no event, no contributor mutation, no writer call.
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { randomUUID } from 'node:crypto';
import { inject, injectable } from 'tsyringe';
import { ContributorLevel, RecognitionKind, } from '../../../domain/generated/output.js';
const CONTRIBUTOR_THRESHOLD_PRS = 1;
const CORE_THRESHOLD_PRS = 5;
const MAINTAINER_THRESHOLD_PRS = 25;
let AwardRecognitionUseCase = class AwardRecognitionUseCase {
    contributors;
    events;
    allContributors;
    constructor(contributors, events, allContributors) {
        this.contributors = contributors;
        this.events = events;
        this.allContributors = allContributors;
    }
    async execute(input) {
        const contributor = await this.contributors.findById(input.contributorId);
        if (!contributor) {
            throw new Error(`Contributor not found: ${input.contributorId}`);
        }
        const occurredAt = input.occurredAt ?? new Date().toISOString();
        const event = {
            id: randomUUID(),
            createdAt: occurredAt,
            updatedAt: occurredAt,
            contributorId: contributor.id,
            kind: input.kind,
            occurredAt,
            prNumber: input.prNumber,
            monthRecapId: input.monthRecapId,
        };
        const { inserted } = await this.events.insert(event);
        if (!inserted) {
            return { awarded: false };
        }
        const updatedContributor = bumpContributor(contributor, input.kind, occurredAt);
        if (updatedContributor !== contributor) {
            await this.contributors.update(updatedContributor);
        }
        await this.allContributors.appendContributor({
            login: updatedContributor.githubLogin,
            contributions: contributionKindsForRecognition(input.kind),
            name: updatedContributor.displayName,
            avatarUrl: updatedContributor.avatarUrl,
        });
        return { awarded: true, event, contributor: updatedContributor };
    }
};
AwardRecognitionUseCase = __decorate([
    injectable(),
    __param(0, inject('IContributorRepository')),
    __param(1, inject('IRecognitionEventRepository')),
    __param(2, inject('IAllContributorsWriter')),
    __metadata("design:paramtypes", [Object, Object, Object])
], AwardRecognitionUseCase);
export { AwardRecognitionUseCase };
function bumpContributor(contributor, kind, occurredAt) {
    if (!isPrKind(kind))
        return contributor;
    const prCount = contributor.prCount + 1;
    const level = nextLevel(contributor.level, prCount);
    return {
        ...contributor,
        prCount,
        level,
        lastContributionAt: occurredAt,
        updatedAt: occurredAt,
    };
}
function isPrKind(kind) {
    return kind === RecognitionKind.FirstPR || kind === RecognitionKind.NthPR;
}
/**
 * Returns the highest contributor ladder level reached by the current level and PR count.
 */
export function nextLevel(current, prCount) {
    if (prCount >= MAINTAINER_THRESHOLD_PRS)
        return highestLevel(current, ContributorLevel.Maintainer);
    if (prCount >= CORE_THRESHOLD_PRS)
        return highestLevel(current, ContributorLevel.Core);
    if (prCount >= CONTRIBUTOR_THRESHOLD_PRS) {
        return highestLevel(current, ContributorLevel.Contributor);
    }
    return current;
}
const LEVEL_ORDER = [
    ContributorLevel.User,
    ContributorLevel.Contributor,
    ContributorLevel.Core,
    ContributorLevel.Maintainer,
];
function highestLevel(a, b) {
    return LEVEL_ORDER.indexOf(a) > LEVEL_ORDER.indexOf(b) ? a : b;
}
function contributionKindsForRecognition(kind) {
    switch (kind) {
        case RecognitionKind.FirstPR:
        case RecognitionKind.NthPR:
            return ['code'];
        case RecognitionKind.FirstIssue:
            return ['bug'];
        case RecognitionKind.MonthlyShoutout:
            return ['ideas'];
    }
}
