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 { injectable, inject } from 'tsyringe';
import { randomUUID } from 'node:crypto';
const VALID_RELATION_TYPES = [
    'Blocking',
    'RelatesTo',
    'Duplicate',
    'StartsBefore',
    'FinishesBefore',
];
let CreateWorkItemRelationUseCase = class CreateWorkItemRelationUseCase {
    relationRepo;
    workItemRepo;
    constructor(relationRepo, workItemRepo) {
        this.relationRepo = relationRepo;
        this.workItemRepo = workItemRepo;
    }
    async execute(input) {
        const { sourceWorkItemId, targetWorkItemId, relationType } = input;
        if (sourceWorkItemId === targetWorkItemId) {
            return { ok: false, error: 'Cannot create a relation from a work item to itself.' };
        }
        if (!VALID_RELATION_TYPES.includes(relationType)) {
            return {
                ok: false,
                error: `Invalid relation type: "${relationType}". Valid types: ${VALID_RELATION_TYPES.join(', ')}`,
            };
        }
        const source = await this.workItemRepo.findById(sourceWorkItemId);
        if (!source) {
            return { ok: false, error: `Source work item not found: "${sourceWorkItemId}"` };
        }
        const target = await this.workItemRepo.findById(targetWorkItemId);
        if (!target) {
            return { ok: false, error: `Target work item not found: "${targetWorkItemId}"` };
        }
        const existing = await this.relationRepo.findExisting(sourceWorkItemId, targetWorkItemId, relationType);
        if (existing) {
            return { ok: false, error: 'This relation already exists.' };
        }
        if (relationType === 'Blocking') {
            const isCircular = await this.detectCircularBlocking(targetWorkItemId, sourceWorkItemId);
            if (isCircular) {
                return {
                    ok: false,
                    error: 'Cannot create relation: would create a circular blocking chain.',
                };
            }
        }
        const now = new Date();
        const relation = {
            id: randomUUID(),
            sourceWorkItemId,
            targetWorkItemId,
            relationType,
            createdAt: now,
        };
        await this.relationRepo.create(relation);
        return { ok: true, relation };
    }
    async detectCircularBlocking(fromId, targetId, visited = new Set()) {
        if (fromId === targetId)
            return true;
        if (visited.has(fromId))
            return false;
        visited.add(fromId);
        const relations = await this.relationRepo.listByWorkItem(fromId);
        const blockingOutgoing = relations.filter((r) => r.relationType === 'Blocking' && r.sourceWorkItemId === fromId);
        for (const rel of blockingOutgoing) {
            if (await this.detectCircularBlocking(rel.targetWorkItemId, targetId, visited)) {
                return true;
            }
        }
        return false;
    }
};
CreateWorkItemRelationUseCase = __decorate([
    injectable(),
    __param(0, inject('IWorkItemRelationRepository')),
    __param(1, inject('IWorkItemRepository')),
    __metadata("design:paramtypes", [Object, Object])
], CreateWorkItemRelationUseCase);
export { CreateWorkItemRelationUseCase };
