// {{generatedComment}}
/* eslint-disable */
// biome-ignore-all lint: generated code
import { connect, type Database } from '@tursodatabase/database';

interface RunResult {
    changes: number;
    lastInsertRowid: number;
}

// Statement type inferred from Database.prepare()
type Statement = Awaited<ReturnType<Database['prepare']>>;

export class {{className}} {
    private statements = new Map<string, Statement>();

    constructor(private db: Database) {}

    private async prepare(id: string, query: string): Promise<Statement> {
        let stmt = this.statements.get(id);
        if (!stmt) {
            stmt = await this.db.prepare(query);
            this.statements.set(id, stmt);
        }
        return stmt;
    }

    static getMigrations(): string[] {
        return [
            {{#each migrations}}
            {{{quote sqlQuery}}},
            {{/each}}
        ];
    }

{{#if config.migrations}}
    static async applyMigrations(db: Database, projectName = '{{projectName}}'): Promise<void> {
        const createStmt = db.prepare(`CREATE TABLE IF NOT EXISTS _sqg_migrations (
            project TEXT NOT NULL,
            migration_id TEXT NOT NULL,
            applied_at TEXT NOT NULL DEFAULT (datetime('now')),
            PRIMARY KEY (project, migration_id)
        )`);
        await createStmt.run();
        const selectStmt = db.prepare('SELECT migration_id FROM _sqg_migrations WHERE project = ?');
        const rows = await selectStmt.all(projectName) as { migration_id: string }[];
        const applied = new Set(rows.map(r => r.migration_id));
        const migrations: [string, string][] = [
            {{#each migrations}}
            ['{{{id}}}', {{{quote sqlQuery}}}],
            {{/each}}
        ];
        const applyFn = db.transaction(async () => {
            for (const [id, sql] of migrations) {
                if (!applied.has(id)) {
                    const execStmt = db.prepare(sql);
                    await execStmt.run();
                    const insertStmt = db.prepare('INSERT INTO _sqg_migrations (project, migration_id) VALUES (?, ?)');
                    await insertStmt.run(projectName, id);
                }
            }
        });
        await applyFn();
    }
{{/if}}

    static getQueryNames(): Map<string, keyof {{className}}> {
        return new Map([
            {{#each queries}} {{#unless skipGenerateFunction}}
            ["{{id}}", "{{functionName}}"],{{/unless}}{{/each}}]
        );
    }

    {{#each queries}}
    {{#unless skipGenerateFunction}}
    async {{functionName}}({{#each variables}}{{name}}: {{type}}{{#unless @last}}, {{/unless}}{{/each}}): Promise<{{> returnType }}> {
        const stmt = await this.prepare('{{id}}',
            {{{quote sqlQuery}}});
        {{> execute}}
    }
    {{/unless}}
    {{/each}}
}

{{#*inline "params"}}{{#each parameterNames}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}{{/inline}}

{{#*inline "paramTypes"}}{{#each parameters}}{{type}} {{#unless @last}}, {{/unless}}{{/each}}{{/inline}}

{{#*inline "columnTypes"}}{{#each columns}}{{name}}: {{mapType .}}{{#unless @last}}, {{/unless}}{{/each}}{{/inline}}

{{#*inline "rowType"}}
{{#if isQuery~}}
{{#if isPluck~}}
{{#if columns.length~}} {{mapType (lookup columns 0)}} {{else}}unknown{{/if~}}
{{~else~}}
{{#if columns.length}}{ {{> columnTypes}} }{{else}}unknown{{/if~}}
{{/if~}}
{{~else~}}
unknown
{{~/if~}}
{{/inline~}}

{{#*inline "resultType"}}
{{#if isQuery~}}
{{> rowType}}
{{~else~}}
unknown
{{~/if~}}
{{/inline~}}


{{#*inline "returnType"}}
{{#if isQuery~}}
{{#if isOne~}}
{{> rowType}} | undefined
{{~else~}}
({{> rowType}})[]
{{/if~}}
{{~else~}}
RunResult
{{~/if~}}
{{/inline~}}

{{#*inline "execute"}}
{{#if isQuery}}
{{#if isOne}}
{{#if isPluck}}
const row = await stmt.get({{> params}}) as Record<string, {{> rowType}}> | undefined;
return row ? Object.values(row)[0] : undefined;
{{else}}
return await stmt.get({{> params}}) as {{> rowType}} | undefined;
{{/if}}
{{else}}
{{#if isPluck}}
const rows = await stmt.all({{> params}}) as Record<string, {{> rowType}}>[];
return rows.map(row => Object.values(row)[0]);
{{else}}
return await stmt.all({{> params}}) as ({{> rowType}})[];
{{/if}}
{{/if}}
{{else}}
const result = await stmt.run({{> params}});
return result as RunResult;
{{/if}}
{{/inline}}
