import assert from 'node:assert';
import database from './database.js';
import safe from 'safetydance';

const APPSTORE_API_TOKEN_KEY = 'appstore_api_token';
const API_SERVER_ORIGIN_KEY = 'api_server_origin';
const AUTOUPDATE_SCHEDULE_KEY = 'autoupdate_schedule';
const AUTOUPDATE_POLICY_KEY = 'autoupdate_policy';
const CLOUDRON_AVATAR_KEY = 'cloudron_avatar';
const CLOUDRON_BACKGROUND_KEY = 'cloudron_background';
const CLOUDRON_ID_KEY = 'cloudron_id';
const CLOUDRON_NAME_KEY = 'cloudron_name';
const CONSOLE_SERVER_ORIGIN_KEY = 'console_server_origin';
const DASHBOARD_DOMAIN_KEY = 'dashboard_domain';
const DASHBOARD_SUBDOMAIN_KEY = 'dashboard_subdomain';
const DIRECTORY_SERVER_KEY = 'directory_server_config';
const DYNAMIC_DNS_KEY = 'dynamic_dns';
const EXTERNAL_LDAP_KEY = 'external_ldap_config';
const FOOTER_KEY = 'footer';
const FIREWALL_BLOCKLIST_KEY = 'firewall_blocklist';
const GHOSTS_CONFIG_KEY = 'ghosts_config';
const IPV4_CONFIG_KEY = 'ipv4_config';
const IPV6_CONFIG_KEY = 'ipv6_config';
const LANGUAGE_KEY = 'language';
const MAIL_DOMAIN_KEY = 'mail_domain';
const MAIL_SUBDOMAIN_KEY = 'mail_subdomain';
const OIDC_COOKIE_SECRET_KEY = 'cookie_secret';
const PROFILE_CONFIG_KEY = 'profile_config';
const REVERSE_PROXY_CONFIG_KEY = 'reverseproxy_config';
const SERVICES_CONFIG_KEY = 'services_config';
const TIME_ZONE_KEY = 'time_zone';
const TRUSTED_IPS_KEY = 'trusted_ips_key';

const SETTINGS_FIELDS = [ 'name', 'value' ].join(',');
const SETTINGS_BLOB_FIELDS = [ 'name', 'valueBlob' ].join(',');

async function get(key) {
    assert.strictEqual(typeof key, 'string');

    const result = await database.query(`SELECT ${SETTINGS_FIELDS} FROM settings WHERE name = ?`, [ key ]);
    if (result.length === 0) return null; // can't return the default value here because we might need to massage/json parse the result

    return result[0].value;
}

async function set(key, value) {
    assert.strictEqual(typeof key, 'string');
    assert(value === null || typeof value === 'string');

    await database.query('INSERT INTO settings (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=VALUES(value)', [ key, value ]); // don't rely on affectedRows here since it gives 2
}

async function getJson(key) {
    assert.strictEqual(typeof key, 'string');

    return safe.JSON.parse(await get(key));
}

async function setJson(key, value) {
    assert.strictEqual(typeof key, 'string');
    assert.strictEqual(typeof value, 'object'); // can be null

    await set(key, value ? JSON.stringify(value) : null);
}

async function getBlob(key) {
    assert.strictEqual(typeof key, 'string');

    const result = await database.query(`SELECT ${SETTINGS_BLOB_FIELDS} FROM settings WHERE name = ?`, [ key ]);
    if (result.length === 0) return null;

    return result[0].valueBlob;
}

async function setBlob(key, value) {
    assert.strictEqual(typeof key, 'string');
    assert(value === null || Buffer.isBuffer(value));

    await database.query('INSERT INTO settings (name, valueBlob) VALUES (?, ?) ON DUPLICATE KEY UPDATE valueBlob=VALUES(valueBlob)', [ key, value ]); // don't rely on affectedRows here since it gives 2
}

async function clear() {
    await database.query('DELETE FROM settings');
}

const WEB_SERVER_ORIGIN_KEY = 'web_server_origin';

const _clear = clear;

export default {
    get,
    set,
    getJson,
    setJson,
    getBlob,
    setBlob,
    APPSTORE_API_TOKEN_KEY,
    API_SERVER_ORIGIN_KEY,
    AUTOUPDATE_SCHEDULE_KEY,
    AUTOUPDATE_POLICY_KEY,
    CLOUDRON_AVATAR_KEY,
    CLOUDRON_BACKGROUND_KEY,
    CLOUDRON_ID_KEY,
    CLOUDRON_NAME_KEY,
    CONSOLE_SERVER_ORIGIN_KEY,
    DASHBOARD_DOMAIN_KEY,
    DASHBOARD_SUBDOMAIN_KEY,
    DIRECTORY_SERVER_KEY,
    DYNAMIC_DNS_KEY,
    EXTERNAL_LDAP_KEY,
    FOOTER_KEY,
    FIREWALL_BLOCKLIST_KEY,
    GHOSTS_CONFIG_KEY,
    IPV4_CONFIG_KEY,
    IPV6_CONFIG_KEY,
    LANGUAGE_KEY,
    MAIL_DOMAIN_KEY,
    MAIL_SUBDOMAIN_KEY,
    OIDC_COOKIE_SECRET_KEY,
    PROFILE_CONFIG_KEY,
    REVERSE_PROXY_CONFIG_KEY,
    SERVICES_CONFIG_KEY,
    TIME_ZONE_KEY,
    TRUSTED_IPS_KEY,
    WEB_SERVER_ORIGIN_KEY,
    _clear,
    _set: set,
};
