'use strict';

const crypto = require('node:crypto'),
    path = require('node:path'),
    safe = require('safetydance');

function getMountPoint(dataDir) {
    const output = safe.child_process.execSync(`df --output=target "${dataDir}" | tail -1`, { encoding: 'utf8' });
    if (!output) return dataDir;
    const mountPoint = output.trim();
    if (mountPoint === '/') return dataDir;
    return mountPoint;
}

exports.up = async function(db) {
    // use safe() here because this migration failed midway in 7.2.4
    await safe(db.runSql('ALTER TABLE apps ADD storageVolumeId VARCHAR(128), ADD FOREIGN KEY(storageVolumeId) REFERENCES volumes(id)'));
    await safe(db.runSql('ALTER TABLE apps ADD storageVolumePrefix VARCHAR(128)'));
    await safe(db.runSql('ALTER TABLE apps ADD CONSTRAINT apps_storageVolume UNIQUE (storageVolumeId, storageVolumePrefix)'));

    const apps = await db.runSql('SELECT * FROM apps WHERE dataDir IS NOT NULL');

    for (const app of apps) {
        const allVolumes = await db.runSql('SELECT * FROM volumes');

        console.log(`data-dir (${app.id}): migrating data dir ${app.dataDir}`);

        const mountPoint = getMountPoint(app.dataDir);
        const prefix = path.relative(mountPoint, app.dataDir);

        console.log(`data-dir (${app.id}): migrating to mountpoint ${mountPoint} and prefix ${prefix}`);

        const volume = allVolumes.find(v => v.hostPath === mountPoint);
        if (volume) {
            console.log(`data-dir (${app.id}): using existing volume ${volume.id}`);
            await db.runSql('UPDATE apps SET storageVolumeId=?, storageVolumePrefix=? WHERE id=?', [ volume.id, prefix, app.id ]);
            continue;
        }

        const id = crypto.randomUUID().replace(/-/g, ''); // to make systemd mount file names more readable
        const name = `appdata-${id}`;
        const type = app.dataDir === mountPoint ? 'filesystem' : 'mountpoint';

        console.log(`data-dir (${app.id}): creating new volume ${id}`);
        await db.runSql('INSERT INTO volumes (id, name, hostPath, mountType, mountOptionsJson) VALUES (?, ?, ?, ?, ?)', [ id, name, mountPoint, type, JSON.stringify({}) ]);
        await db.runSql('UPDATE apps SET storageVolumeId=?, storageVolumePrefix=? WHERE id=?', [ id, prefix, app.id ]);
    }

    await db.runSql('ALTER TABLE apps DROP COLUMN dataDir');
};

exports.down = async function(/*db*/) {
};
