// {{generatedComment}}
/* eslint-disable */
// biome-ignore-all lint: generated code
import type { Client, InArgs } from '@libsql/client';

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

export class {{className}} {
    constructor(private client: Client) {}

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

{{#if config.migrations}}
    static async applyMigrations(client: Client, projectName = '{{projectName}}'): Promise<void> {
        await client.execute({
            sql: `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)
            )`,
            args: [],
        });
        const tx = await client.transaction('write');
        try {
            const result = await tx.execute({
                sql: 'SELECT migration_id FROM _sqg_migrations WHERE project = ?',
                args: [projectName],
            });
            const applied = new Set(result.rows.map(r => r.migration_id as string));
            const migrations: [string, string][] = [
                {{#each migrations}}
                ['{{{id}}}', {{{quote sqlQuery}}}],
                {{/each}}
            ];
            for (const [id, sql] of migrations) {
                if (!applied.has(id)) {
                    await tx.execute({ sql, args: [] });
                    await tx.execute({
                        sql: 'INSERT INTO _sqg_migrations (project, migration_id) VALUES (?, ?)',
                        args: [projectName, id],
                    });
                }
            }
            await tx.commit();
        } catch (e) {
            await tx.rollback();
            throw e;
        }
    }
{{/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 result = await this.client.execute({
            sql: {{{quote sqlQuery}}},
            args: [{{> params}}] as InArgs,
        });
        {{> 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 = result.rows[0];
return row ? Object.values(row)[0] as {{> rowType}} : undefined;
{{else}}
return (result.rows as unknown[])[0] as {{> rowType}} | undefined;
{{/if}}
{{else}}
{{#if isPluck}}
return result.rows.map(row => Object.values(row)[0] as {{> rowType}});
{{else}}
return (result.rows as unknown[]) as ({{> rowType}})[];
{{/if}}
{{/if}}
{{else}}
return {
    changes: result.rowsAffected,
    lastInsertRowid: result.lastInsertRowid ?? 0n,
};
{{/if}}
{{/inline}}
