"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processUndoActivity = void 0;
const tslib_1 = require("tslib");
const video_1 = require("../../../models/video/video");
const database_utils_1 = require("../../../helpers/database-utils");
const logger_1 = require("../../../helpers/logger");
const database_1 = require("../../../initializers/database");
const account_video_rate_1 = require("../../../models/account/account-video-rate");
const actor_1 = require("../../../models/actor/actor");
const actor_follow_1 = require("../../../models/actor/actor-follow");
const video_redundancy_1 = require("../../../models/redundancy/video-redundancy");
const video_share_1 = require("../../../models/video/video-share");
const send_utils_1 = require("../send/shared/send-utils");
const videos_1 = require("../videos");
function processUndoActivity(options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { activity, byActor } = options;
        const activityToUndo = activity.object;
        if (activityToUndo.type === 'Like') {
            return (0, database_utils_1.retryTransactionWrapper)(processUndoLike, byActor, activity);
        }
        if (activityToUndo.type === 'Create') {
            if (activityToUndo.object.type === 'CacheFile') {
                return (0, database_utils_1.retryTransactionWrapper)(processUndoCacheFile, byActor, activity);
            }
        }
        if (activityToUndo.type === 'Dislike') {
            return (0, database_utils_1.retryTransactionWrapper)(processUndoDislike, byActor, activity);
        }
        if (activityToUndo.type === 'Follow') {
            return (0, database_utils_1.retryTransactionWrapper)(processUndoFollow, byActor, activityToUndo);
        }
        if (activityToUndo.type === 'Announce') {
            return (0, database_utils_1.retryTransactionWrapper)(processUndoAnnounce, byActor, activityToUndo);
        }
        logger_1.logger.warn('Unknown activity object type %s -> %s when undo activity.', activityToUndo.type, { activity: activity.id });
        return undefined;
    });
}
exports.processUndoActivity = processUndoActivity;
function processUndoLike(byActor, activity) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const likeActivity = activity.object;
        const { video: onlyVideo } = yield (0, videos_1.getOrCreateAPVideo)({ videoObject: likeActivity.object });
        if (!onlyVideo.isOwned())
            return;
        return database_1.sequelizeTypescript.transaction((t) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!byActor.Account)
                throw new Error('Unknown account ' + byActor.url);
            const video = yield video_1.VideoModel.loadFull(onlyVideo.id, t);
            const rate = yield account_video_rate_1.AccountVideoRateModel.loadByAccountAndVideoOrUrl(byActor.Account.id, video.id, likeActivity.id, t);
            if (!rate || rate.type !== 'like') {
                logger_1.logger.warn('Unknown like by account %d for video %d.', byActor.Account.id, video.id);
                return;
            }
            yield rate.destroy({ transaction: t });
            yield video.decrement('likes', { transaction: t });
            video.likes--;
            yield (0, videos_1.federateVideoIfNeeded)(video, false, t);
        }));
    });
}
function processUndoDislike(byActor, activity) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const dislike = activity.object.type === 'Dislike'
            ? activity.object
            : activity.object.object;
        const { video: onlyVideo } = yield (0, videos_1.getOrCreateAPVideo)({ videoObject: dislike.object });
        if (!onlyVideo.isOwned())
            return;
        return database_1.sequelizeTypescript.transaction((t) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!byActor.Account)
                throw new Error('Unknown account ' + byActor.url);
            const video = yield video_1.VideoModel.loadFull(onlyVideo.id, t);
            const rate = yield account_video_rate_1.AccountVideoRateModel.loadByAccountAndVideoOrUrl(byActor.Account.id, video.id, dislike.id, t);
            if (!rate || rate.type !== 'dislike') {
                logger_1.logger.warn(`Unknown dislike by account %d for video %d.`, byActor.Account.id, video.id);
                return;
            }
            yield rate.destroy({ transaction: t });
            yield video.decrement('dislikes', { transaction: t });
            video.dislikes--;
            yield (0, videos_1.federateVideoIfNeeded)(video, false, t);
        }));
    });
}
function processUndoCacheFile(byActor, activity) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const cacheFileObject = activity.object.object;
        const { video } = yield (0, videos_1.getOrCreateAPVideo)({ videoObject: cacheFileObject.object });
        return database_1.sequelizeTypescript.transaction((t) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            const cacheFile = yield video_redundancy_1.VideoRedundancyModel.loadByUrl(cacheFileObject.id, t);
            if (!cacheFile) {
                logger_1.logger.debug('Cannot undo unknown video cache %s.', cacheFileObject.id);
                return;
            }
            if (cacheFile.actorId !== byActor.id)
                throw new Error('Cannot delete redundancy ' + cacheFile.url + ' of another actor.');
            yield cacheFile.destroy({ transaction: t });
            if (video.isOwned()) {
                const exceptions = [byActor];
                yield (0, send_utils_1.forwardVideoRelatedActivity)(activity, t, exceptions, video);
            }
        }));
    });
}
function processUndoAnnounce(byActor, announceActivity) {
    return database_1.sequelizeTypescript.transaction((t) => tslib_1.__awaiter(this, void 0, void 0, function* () {
        const share = yield video_share_1.VideoShareModel.loadByUrl(announceActivity.id, t);
        if (!share) {
            logger_1.logger.warn('Unknown video share %d', announceActivity.id);
            return;
        }
        if (share.actorId !== byActor.id)
            throw new Error(`${share.url} is not shared by ${byActor.url}.`);
        yield share.destroy({ transaction: t });
        if (share.Video.isOwned()) {
            const exceptions = [byActor];
            yield (0, send_utils_1.forwardVideoRelatedActivity)(announceActivity, t, exceptions, share.Video);
        }
    }));
}
function processUndoFollow(follower, followActivity) {
    return database_1.sequelizeTypescript.transaction((t) => tslib_1.__awaiter(this, void 0, void 0, function* () {
        const following = yield actor_1.ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t);
        const actorFollow = yield actor_follow_1.ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t);
        if (!actorFollow) {
            logger_1.logger.warn('Unknown actor follow %d -> %d.', follower.id, following.id);
            return;
        }
        yield actorFollow.destroy({ transaction: t });
        return undefined;
    }));
}
//# sourceMappingURL=process-undo.js.map