import {
    StandardsConfigSchema,
} from "@blade-and-brawn/calculator";
import { Value } from "@sinclair/typebox/value";
import { db } from "./db";
import { DEFAULT_NAME, env, log } from "../util";
import standardsConfig from "./seed-data/standards-config.json" with {type: "json"};

Value.Assert(StandardsConfigSchema, standardsConfig);

async function seedStandardsDataset(): Promise<string> {
    const existing = await db.selectFrom("standards_datasets")
        .select(["id"])
        .where("name", "=", DEFAULT_NAME)
        .executeTakeFirst();
    if (existing) {
        log.info({ id: existing.id }, "default standards dataset already seeded, skipping");
        return existing.id;
    }

    const result = await db.insertInto("standards_datasets")
        .values({ name: DEFAULT_NAME, data: standardsConfig.data })
        .returning("id")
        .executeTakeFirstOrThrow();
    log.info({ id: result.id }, "seeded default standards dataset");
    return result.id;
}

async function seedStandardsConfig(datasetId: string): Promise<string> {
    const existing = await db.selectFrom("standards_configs")
        .select(["id"])
        .where("name", "=", DEFAULT_NAME)
        .executeTakeFirst();
    if (existing) {
        log.info({ id: existing.id }, "default standards config already seeded, skipping");
        return existing.id;
    }

    const result = await db.insertInto("standards_configs")
        .values({
            name: DEFAULT_NAME,
            dataset_id: datasetId,
            params: standardsConfig.params,
        })
        .returning("id")
        .executeTakeFirstOrThrow();
    log.info({ id: result.id }, "seeded default standards config");
    return result.id;
}

async function seedCalculator(standardsConfigId: string): Promise<void> {
    const existing = await db.selectFrom("calculators")
        .select(["id"])
        .where("name", "=", DEFAULT_NAME)
        .executeTakeFirst();
    if (existing) {
        log.info({ id: existing.id }, "default calculator already seeded, skipping");
        return;
    }

    const result = await db.insertInto("calculators")
        .values({
            name: DEFAULT_NAME,
            standards_config_id: standardsConfigId
        })
        .returning("id")
        .executeTakeFirstOrThrow();
    log.info({ id: result.id }, "seeded default calculator");
}

(async () => {
    const answer = prompt(`Seed the database (${env.DATABASE_URL}) with default standards data? (y/N)`);
    if (answer?.trim().toLowerCase() !== "y") {
        log.info("Aborted");
        await db.destroy();
        return;
    }

    try {
        const datasetId = await seedStandardsDataset();
        const standardsConfigId = await seedStandardsConfig(datasetId);
        await seedCalculator(standardsConfigId);
        log.info("seed finished");
    }
    catch (err) {
        log.error({ err }, "seed failed");
        process.exit(1);
    }
    finally {
        await db.destroy();
    }
})();
