/**
 * Concrete EntityWriter implementation for M17 restore (Phase 6).
 *
 * Constructed per-restore-request by ReleaseService — looks up entity
 * services + tag/junction services from the plugin host. Each write goes
 * through the normal service API so the mutation is captured into
 * `entity_version` with `release_id = NULL` (append-only — decyzja 7).
 *
 * Idempotent UPSERT semantics (decyzja 11): no `--force` flag, no
 * destructive operations on history. The append-only safety net makes
 * accidental overwrites cofalne by another restore.
 */
import { DomainError } from './tags.js';
export class HostEntityWriter {
    host;
    tags;
    constructor(host, tags) {
        this.host = host;
        this.tags = tags;
    }
    upsertEndpoint(slug, input, actor) {
        const service = this.requireService('endpoint');
        const result = service.upsert(slug, input, actor);
        return { entity: result.entity, op: result.op };
    }
    upsertDto(slug, input, actor) {
        const service = this.requireService('dto');
        const result = service.upsert(slug, input, actor);
        return { entity: result.dto, op: result.op };
    }
    upsertDatabaseTable(slug, input, actor) {
        const service = this.requireService('database-table');
        const result = service.upsert(slug, input, actor);
        return { entity: result.dbTable, op: result.op, warnings: result.warnings };
    }
    upsertUiView(slug, input, actor) {
        const service = this.requireService('ui-view');
        const result = service.upsert(slug, input, actor);
        return { entity: result.uiView, op: result.op, warnings: result.warnings };
    }
    upsertAc(slug, input, actor) {
        const service = this.requireService('ac');
        const result = service.upsert(slug, input, actor);
        return { entity: result.ac, op: result.op };
    }
    syncEndpointDtos(endpointSlug, target) {
        const service = this.requireService('endpoint');
        const ep = service.getBySlug(endpointSlug);
        if (!ep)
            return { linked: 0, unlinked: 0, warnings: [`endpoint '${endpointSlug}' not found`] };
        const keyOf = (l) => `${l.relation}|${l.dtoSlug}|${l.statusCode ?? 'null'}`;
        const currentSet = new Map(ep.dtos.map((l) => [keyOf(l), l]));
        const targetSet = new Map(target.map((l) => [keyOf(l), l]));
        let linked = 0;
        let unlinked = 0;
        const warnings = [];
        // Unlink extras first to avoid conflicts on UNIQUE constraint
        for (const [k, current] of currentSet) {
            if (!targetSet.has(k)) {
                try {
                    service.unlinkDto(endpointSlug, current.dtoSlug, current.relation, current.statusCode);
                    unlinked += 1;
                }
                catch (err) {
                    warnings.push(`unlink '${k}' failed: ${err.message}`);
                }
            }
        }
        // Link missing
        for (const [k, want] of targetSet) {
            if (!currentSet.has(k)) {
                try {
                    service.linkDto(endpointSlug, want.dtoSlug, want.relation, want.statusCode);
                    linked += 1;
                }
                catch (err) {
                    warnings.push(`link '${k}' failed: ${err.message}`);
                }
            }
        }
        return { linked, unlinked, warnings };
    }
    syncTags(type, slug, tags) {
        const id = this.host.resolveEntityId(type, slug);
        if (id == null)
            return;
        this.tags.assignTags(type, id, tags);
    }
    delete(type, slug, actor) {
        switch (type) {
            case 'endpoint': {
                const service = this.requireService('endpoint');
                if (!service.getBySlug(slug))
                    return { deleted: false };
                service.remove(slug, actor);
                return { deleted: true };
            }
            case 'dto': {
                const service = this.requireService('dto');
                if (!service.getBySlug(slug))
                    return { deleted: false };
                service.remove(slug, actor);
                return { deleted: true };
            }
            case 'database-table': {
                const service = this.requireService('database-table');
                if (!service.getBySlug(slug))
                    return { deleted: false };
                service.remove(slug, actor);
                return { deleted: true };
            }
            case 'ui-view': {
                const service = this.requireService('ui-view');
                if (!service.getBySlug(slug))
                    return { deleted: false };
                service.remove(slug, actor);
                return { deleted: true };
            }
            case 'ac': {
                const service = this.requireService('ac');
                if (!service.getBySlug(slug))
                    return { deleted: false };
                service.remove(slug, actor);
                return { deleted: true };
            }
            default:
                return { deleted: false };
        }
    }
    requireService(type) {
        const service = this.host.getEntityService(type);
        if (!service)
            throw new DomainError('VALIDATION', `entity service for type '${type}' not registered`);
        return service;
    }
}
//# sourceMappingURL=entity-writer.js.map