"use strict";
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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CliService = void 0;
const common_1 = require("@nestjs/common");
const node_path_1 = require("node:path");
const constants_1 = require("../constants");
const user_dto_1 = require("../dtos/user.dto");
const enum_1 = require("../enum");
const base_service_1 = require("./base.service");
const maintenance_1 = require("../utils/maintenance");
const misc_1 = require("../utils/misc");
let CliService = class CliService extends base_service_1.BaseService {
    async schemaReport() {
        const allFiles = await this.storageRepository.readdir((0, node_path_1.join)(__dirname, '../schema/migrations'));
        const files = allFiles.filter((file) => file.endsWith('.js')).map((file) => file.slice(0, -3));
        const rows = await this.databaseRepository.getMigrations();
        const filesSet = new Set(files);
        const rowsSet = new Set(rows.map((item) => item.name));
        const combined = [...filesSet, ...rowsSet].toSorted();
        const migrations = [];
        for (const name of combined) {
            if (filesSet.has(name) && rowsSet.has(name)) {
                migrations.push({ name, status: 'applied' });
                continue;
            }
            if (filesSet.has(name) && !rowsSet.has(name)) {
                migrations.push({ name, status: 'missing' });
                continue;
            }
            if (!filesSet.has(name) && rowsSet.has(name)) {
                migrations.push({ name, status: 'deleted' });
            }
        }
        const drift = await this.databaseRepository.getSchemaDrift();
        return { migrations, drift };
    }
    async listUsers() {
        const users = await this.userRepository.getList({ withDeleted: true });
        return users.map((user) => (0, user_dto_1.mapUserAdmin)(user));
    }
    async resetAdminPassword(ask) {
        const admin = await this.userRepository.getAdmin();
        if (!admin) {
            throw new Error('Admin account does not exist');
        }
        const { newPassword: providedPassword, invalidateSessions } = await ask((0, user_dto_1.mapUserAdmin)(admin));
        const password = providedPassword || this.cryptoRepository.randomBytesAsText(24);
        const hashedPassword = await this.cryptoRepository.hashBcrypt(password, constants_1.SALT_ROUNDS);
        await this.userRepository.update(admin.id, { password: hashedPassword });
        if (invalidateSessions) {
            await this.sessionRepository.invalidateAll({ userId: admin.id });
        }
        return { admin, password, provided: !!providedPassword };
    }
    async disablePasswordLogin() {
        const config = await this.getConfig({ withCache: false });
        config.passwordLogin.enabled = false;
        await this.updateConfig(config);
    }
    async enablePasswordLogin() {
        const config = await this.getConfig({ withCache: false });
        config.passwordLogin.enabled = true;
        await this.updateConfig(config);
    }
    async disableMaintenanceMode() {
        const currentState = (await this.systemMetadataRepository.get(enum_1.SystemMetadataKey.MaintenanceMode)) ?? {
            isMaintenanceMode: false,
        };
        if (!currentState.isMaintenanceMode) {
            return {
                alreadyDisabled: true,
            };
        }
        const state = { isMaintenanceMode: false };
        await this.systemMetadataRepository.set(enum_1.SystemMetadataKey.MaintenanceMode, state);
        await this.appRepository.sendOneShotAppRestart(state);
        return {
            alreadyDisabled: false,
        };
    }
    async enableMaintenanceMode() {
        const { server } = await this.getConfig({ withCache: true });
        const baseUrl = (0, misc_1.getExternalDomain)(server);
        const payload = {
            username: 'cli-admin',
        };
        const state = (await this.systemMetadataRepository.get(enum_1.SystemMetadataKey.MaintenanceMode)) ?? {
            isMaintenanceMode: false,
        };
        if (state.isMaintenanceMode) {
            return {
                authUrl: await (0, maintenance_1.createMaintenanceLoginUrl)(baseUrl, payload, state.secret),
                alreadyEnabled: true,
            };
        }
        const secret = (0, maintenance_1.generateMaintenanceSecret)();
        await this.systemMetadataRepository.set(enum_1.SystemMetadataKey.MaintenanceMode, {
            isMaintenanceMode: true,
            secret,
            action: {
                action: enum_1.MaintenanceAction.Start,
            },
        });
        await this.appRepository.sendOneShotAppRestart({
            isMaintenanceMode: true,
        });
        return {
            authUrl: await (0, maintenance_1.createMaintenanceLoginUrl)(baseUrl, payload, secret),
            alreadyEnabled: false,
        };
    }
    async grantAdminAccess(email) {
        const user = await this.userRepository.getByEmail(email);
        if (!user) {
            throw new Error('User does not exist');
        }
        await this.userRepository.update(user.id, { isAdmin: true });
    }
    async revokeAdminAccess(email) {
        const user = await this.userRepository.getByEmail(email);
        if (!user) {
            throw new Error('User does not exist');
        }
        await this.userRepository.update(user.id, { isAdmin: false });
    }
    async disableOAuthLogin() {
        const config = await this.getConfig({ withCache: false });
        config.oauth.enabled = false;
        await this.updateConfig(config);
    }
    async enableOAuthLogin() {
        const config = await this.getConfig({ withCache: false });
        config.oauth.enabled = true;
        await this.updateConfig(config);
    }
    async getSampleFilePaths() {
        const [assets, people, users] = await Promise.all([
            this.assetRepository.getFileSamples(),
            this.personRepository.getFileSamples(),
            this.userRepository.getFileSamples(),
        ]);
        const paths = Array.from(people, (person) => person.thumbnailPath);
        for (const user of users) {
            paths.push(user.profileImagePath);
        }
        for (const asset of assets) {
            paths.push(asset.path);
        }
        return paths.filter(Boolean);
    }
    async migrateFilePaths({ oldValue, newValue, confirm, }) {
        let sourceFolder = oldValue;
        if (sourceFolder.startsWith('./')) {
            sourceFolder = sourceFolder.slice(2);
        }
        const targetFolder = newValue;
        if (!(0, node_path_1.isAbsolute)(targetFolder)) {
            throw new Error('Target media location must be an absolute path');
        }
        if (!(await confirm({ sourceFolder, targetFolder }))) {
            return false;
        }
        await this.databaseRepository.migrateFilePaths(sourceFolder, targetFolder);
        return true;
    }
    cleanup() {
        return this.databaseRepository.shutdown();
    }
};
exports.CliService = CliService;
exports.CliService = CliService = __decorate([
    (0, common_1.Injectable)()
], CliService);
//# sourceMappingURL=cli.service.js.map