package got

import (
	"text/template"

	. "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common"
	G "github.com/dave/jennifer/jen"
	// "github.com/davecgh/go-spew/spew"
)

var (
	patchStmtsTmpl, patchRelationStmtsTmpl *template.Template
	patchStmtsErr                          error
)

func init() {

	patchStmtsTmpl, patchStmtsErr = ParseTemplate(`
	var (
		patchs = &models.{{.entity}}Patchs{Set: &models.{{.entity}}Input{}}
		entity = patchs.Set
	)

	if err = api.ReadJson(ctx, patchs); err != nil {
		return
	}

	entity.SetMode("patch")
	values := ctx.Values()
	values.Set("patchs", patchs)
	entity.LastUpdate = api.NowUnix()
	user := values.Get("$user.ref").(*models.UserReference)
	entity.UpdatedBy = user
	values.Set("entity", entity)
	{{if .entityAlias }} 
	values.Set("{{.entityAlias}}", entity) 
	values.Set("{{.entityAlias}}.patch", patchs)
	{{end}}
	
	{{if .preconditions}}
		if _, err = executeAction(
			ctx,
			{{.preconditions}},
		); err != nil {
			return
		}
	{{end}}

	options := values.Get("$filter").(*api.Filter)

	options.DB = "{{.dbName}}"
	options.Collection = "{{.collectionName}}"
	options.Patchs, options.Options = patchs.Patch()
	api.Dump(options.Options)

	if _, err = models.Api.PatchOne(options); err != nil {

		err.Details(&errs.Detail{
			Dominio:      "",
			Reason:       "",
			Location:     "middleware.path",
			LocationType: "middleware.operation/{{.entity}}",
		})

		return
	}

	options.Entity = &models.{{.entity}}{}

	if _, err = models.Api.FindOne(options); err != nil {

		err.Details(&errs.Detail{
			Dominio:      "",
			Reason:       "",
			Location:     "middleware.findOne",
			LocationType: "middleware.operation/{{.entity}}",
		})

		return
	}

	values.Set("{{.entityAlias}}.after.patch", options.Entity)

	{{if .hasUpdateRelation}} // Cria uma thread que executa a atualizaca das referências.
	go func() {
		UpdateRelation{{.entity}}(options)
	}()	{{end}}

	{{if .beforeResponse}}
		if resp, err = executeAction(
			ctx,
			{{.beforeResponse}},
		); err != nil || resp != nil {
		return
	}
	{{end}}
	resp = options.Entity
	return`)

	if patchStmtsErr != nil {
		panic(patchStmtsErr)
	}

}

var (
	GenPatchStmts = &Middleware{
		Id:   "implement",
		Type: "method",
		Fn: func(ctx *MiddlewareContext) error {
			var (
				project          = ctx.Project
				method           = ctx.Method
				dbName           = project.GetEntityDB(method.Entity)
				collectionName   = project.GetCollection(method.Entity)
				dependenceMethod = BASE_HAS_DEPENDE + method.Entity
				beforeSend       = method.Hook("beforeSend")
				beforePersist    = method.Hook("beforePersist")
				context          = map[string]interface{}{
					"dbName":            dbName,
					"collectionName":    collectionName,
					"entity":            method.Entity,
					"dependenceMethod":  dependenceMethod,
					"beforePersist":     beforePersist,
					"beforeSend":        beforeSend,
					"hasUpdateRelation": SR.Has(method.Entity),
					"preconditions":     parseMethodActions(method.Preconditions),
					"beforeResponse":    parseMethodActions(method.BeforeResponse),
					"entityAlias":       getCustom(method.Custom, "go.entity.alias"),
				}
			)

			if beforePersist {
				generateHookCall(project, method, "beforePersist")
			}
			if beforeSend {
				generateHookCall(project, method, "beforeSend")
			}

			// Nome do metodo que verifica se a entidade tem dependencias
			out, _ := TemplateToString(patchStmtsTmpl, context)
			afterMethod := ctx.Statement.Block(G.Id(out)).Line()

			if body, err := createUpdateRelationMethod(method, context); err == nil {
				afterMethod.Id(body)
			}

			return nil
		},
	}
)
