package gen

import (
	"fmt"
	"os"
	"strings"
	"text/template"

	"github.com/Masterminds/sprig/v3"

	"agola.io/agola/internal/sqlg"
)

type MethodsData struct {
	Version   uint
	Sequences []string
}

func genMethodsData(gd *genData) MethodsData {
	objectsInfo := []sqlg.ObjectInfo{}
	for _, oi := range gd.ObjectsInfo {
		oi.Fields = append(objectMetaFields(), oi.Fields...)

		objectsInfo = append(objectsInfo, oi)
	}

	objectsInfo = sqlg.PopulateObjectsInfo(objectsInfo, "")

	data := MethodsData{
		Version: gd.Version,
	}

	for _, oi := range objectsInfo {
		tableDef := DMLGenericDataTable{Table: oi.Table, ObjectName: oi.Name}
		tableDef.LowerObjectName = strings.ToLower(oi.Name)
		tableDef.LowerCamelObjectName = ToLowerCamel(oi.Name)
		tableDef.FuncPrefix = ToLowerCamel(oi.Name)

		for _, of := range oi.Fields {
			colName := of.ColName

			if of.Sequence {
				sequenceName := fmt.Sprintf("%s_%s_seq", oi.Table, colName)
				data.Sequences = append(data.Sequences, sequenceName)
			}
		}
	}

	return data
}

func genMethods(gd *genData) {
	data := genMethodsData(gd)

	f, err := os.Create("methods.go")
	if err != nil {
		panic(err)
	}

	defer f.Close()

	if err := methodsTemplate.Execute(f, data); err != nil {
		panic(err)
	}
}

var methodsTemplate = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Funcs(funcs).Parse(`
// Code generated by go generate; DO NOT EDIT.
package db

import (
	stdsql "database/sql"

	"agola.io/agola/internal/sqlg"
	"agola.io/agola/internal/sqlg/sql"

	"github.com/sorintlab/errors"
)

func (d *DB) Version() uint { return {{ $.Version }} }

func (d *DB) DDL() []string {
	switch d.DBType() {
	case sql.Postgres:
		return DDLPostgres
	case sql.Sqlite3:
		return DDLSqlite3
	}

	return nil
}

func (d *DB) Sequences() []sqlg.Sequence {
	return Sequences
}

func (d *DB) scanArray(rows *stdsql.Rows, colsList ...[]any) error {
	fields := []any{}
	for _, cols := range colsList {
		fields = append(fields, cols...)
	}
	if err := rows.Scan(fields...); err != nil {
		return errors.Wrap(err, "failed to scan row")
	}

	return nil
}
`))
