package bun

import (
	"bytes"
	"text/template"
)

// modelTemplate defines the template for generating Bun models
const modelTemplate = `// Code generated by relspecgo. DO NOT EDIT.
package {{.PackageName}}

{{if .Imports -}}
import (
{{range .Imports -}}
	{{.}}
{{end -}}
)
{{end}}
{{range .Models}}
{{if .Comment}}// {{.Comment}}{{end}}
type {{.Name}} struct {
	bun.BaseModel ` + "`bun:\"table:{{.TableName}},alias:{{.TableNameOnly}}\"`" + `
{{- range .Fields}}
	{{.Name}} {{.Type}} ` + "`bun:\"{{.BunTag}}\" json:\"{{.JSONTag}}\"`" + `{{if .Comment}} // {{.Comment}}{{end}}
{{- end}}
{{- if .ExtraFields}}

	// --- Custom fields (managed by relspecgo generator config, issue #4) ---
{{- range .ExtraFields}}
	{{.Name}} {{.Type}} ` + "`bun:\"{{.BunTag}}\" json:\"{{.JSONTag}}\"`" + `{{if .Comment}} // {{.Comment}}{{end}}
{{- end}}
{{- end}}
}
{{if .Config.GenerateTableName}}
// TableName returns the table name for {{.Name}}
func (m {{.Name}}) TableName() string {
	return "{{.TableName}}"
}
{{end}}
{{if .Config.GenerateTableNameOnly}}
// TableNameOnly returns the table name without schema for {{.Name}}
func (m {{.Name}}) TableNameOnly() string {
	return "{{.TableNameOnly}}"
}
{{end}}
{{if .Config.GenerateSchemaName}}
// SchemaName returns the schema name for {{.Name}}
func (m {{.Name}}) SchemaName() string {
	return "{{.SchemaName}}"
}
{{end}}
{{if and .Config.GenerateGetID .PrimaryKeyField}}
// GetID returns the primary key value
func (m {{.Name}}) GetID() {{.PrimaryKeyIDType}} {
	{{if .PrimaryKeyIsSQL -}}
	{{if .PrimaryKeyIsStr -}}
	return m.{{.PrimaryKeyField}}.String()
	{{- else -}}
	return m.{{.PrimaryKeyField}}.Int64()
	{{- end}}
	{{- else -}}
	{{if .PrimaryKeyIsStr -}}
	return m.{{.PrimaryKeyField}}
	{{- else -}}
	return int64(m.{{.PrimaryKeyField}})
	{{- end}}
	{{- end}}
}
{{end}}
{{if and .Config.GenerateGetIDStr .PrimaryKeyField}}
// GetIDStr returns the primary key as a string
func (m {{.Name}}) GetIDStr() string {
	{{if .PrimaryKeyIsSQL -}}
	return m.{{.PrimaryKeyField}}.String()
	{{- else if .PrimaryKeyIsStr -}}
	return m.{{.PrimaryKeyField}}
	{{- else -}}
	return fmt.Sprintf("%d", m.{{.PrimaryKeyField}})
	{{- end}}
}
{{end}}
{{if and .Config.GenerateSetID .PrimaryKeyField}}
// SetID sets the primary key value
func (m {{.Name}}) SetID(newid {{.PrimaryKeyIDType}}) {
	m.UpdateID(newid)
}
{{end}}
{{if and .Config.GenerateUpdateID .PrimaryKeyField}}
// UpdateID updates the primary key value
func (m *{{.Name}}) UpdateID(newid {{.PrimaryKeyIDType}}) {
	{{if .PrimaryKeyIsSQL -}}
	{{if .PrimaryKeyIsStr -}}
	m.{{.PrimaryKeyField}}.FromString(newid)
	{{- else -}}
	m.{{.PrimaryKeyField}}.FromString(fmt.Sprintf("%d", newid))
	{{- end}}
	{{- else -}}
	{{if .PrimaryKeyIsStr -}}
	m.{{.PrimaryKeyField}} = newid
	{{- else -}}
	m.{{.PrimaryKeyField}} = {{.PrimaryKeyType}}(newid)
	{{- end}}
	{{- end}}
}
{{end}}
{{if and .Config.GenerateGetIDName .IDColumnName}}
// GetIDName returns the name of the primary key column
func (m {{.Name}}) GetIDName() string {
	return "{{.IDColumnName}}"
}
{{end}}
{{if .Config.GenerateGetPrefix}}
// GetPrefix returns the table prefix
func (m {{.Name}}) GetPrefix() string {
	return "{{.Prefix}}"
}
{{end}}
{{end -}}
`

// Templates holds the parsed templates
type Templates struct {
	modelTmpl *template.Template
}

// NewTemplates creates and parses the templates
func NewTemplates() (*Templates, error) {
	modelTmpl, err := template.New("model").Parse(modelTemplate)
	if err != nil {
		return nil, err
	}

	return &Templates{
		modelTmpl: modelTmpl,
	}, nil
}

// GenerateCode executes the template with the given data
func (t *Templates) GenerateCode(data *TemplateData) (string, error) {
	var buf bytes.Buffer
	err := t.modelTmpl.Execute(&buf, data)
	if err != nil {
		return "", err
	}

	return buf.String(), nil
}
