package controllers

import (
	"encoding/json"
	"oc-datacenter/infrastructure"

	oclib "cloud.o-forge.io/core/oc-lib"
	"cloud.o-forge.io/core/oc-lib/models/live"
	beego "github.com/beego/beego/v2/server/web"
)

type MinioController struct {
	beego.Controller
}


// @Title CreateServiceAccounnt
// @Description Add a new ServiceAccount to a Minio server using its ID and an execution ID and store the secret holding the login in the appropriate namespace
// @Success 200
// @Param	executions	path	string				true	"The executionsID of the execution"
// @Param	minioId		path	string				true	"The ID of the Minio you want to reach"
// @Param 	retrieve	body	map[string]string	false	"Should be empty or contain "'retrieve': true"
// @router	/serviceaccount/:minioId/:executions [post]
func (m *MinioController) CreateServiceAccount() {
	_, peerID, _ := oclib.ExtractTokenInfo(*m.Ctx.Request)
	// This part is solely for dev purposes and should be removed once test on 

 
	executionsId := m.Ctx.Input.Param(":executions")
	minioId := m.Ctx.Input.Param(":minioId")

	var b map[string]interface{}
	retrieve := false
	json.Unmarshal(m.Ctx.Input.CopyBody(10000), &b)
	if r, ok :=  b["retrieve"]; ok {
		retrieve = r.(bool)
	}

	// retrieve the live storage with the minioId 
	access, secret, ok := m.createServiceAccount(minioId, peerID, executionsId)
	if !ok {
		return
	}

	if retrieve {
		m.Ctx.Output.SetStatus(201)
		m.Data["json"] = map[string]string{"access": access, "secret": secret}
		m.ServeJSON()
		return
	}

	// test if the namespace exists
	k, err := infrastructure.NewService()
	if err != nil {
		m.Ctx.Output.SetStatus(500)
		m.Data["json"] = map[string]string{"error": err.Error()}
		m.ServeJSON()
		return
	}

	ns, err := k.GetNamespace(m.Ctx.Request.Context(), executionsId)
	if ns == nil {
		m.Ctx.Output.SetStatus(403)
		m.Data["json"] = map[string]string{"error":"Could not find the namespace corresponding to executionsID " + executionsId}
		m.ServeJSON()
		return
	}
	if err != nil {
		m.Ctx.Output.SetStatus(500)
		m.Data["json"] = map[string]string{"error": "Error when trying to check if namespace " + executionsId + " exists : " + err.Error()}
		m.ServeJSON()
		return
	}

	// store the credentials in the namespace
	err = k.CreateSecret(m.Ctx.Request.Context(), minioId, executionsId, access, secret)
	if err != nil {
		m.Ctx.Output.SetStatus(500)
		m.Data["json"] = map[string]string{"error": "Error when storing Minio serviceAccount credentials in namespace " + executionsId + " exists : " + err.Error()}
		m.ServeJSON()
		return
	}

	m.Data["json"] = map[string]string{"success": "created secret " + executionsId + "-secret-sa in namespace ns-" + executionsId}
	m.ServeJSON()
}



func (m *MinioController) createServiceAccount(minioId string, peerID string, executionsId string) (string, string, bool) {
	s := oclib.NewRequest(oclib.LibDataEnum(oclib.STORAGE_RESOURCE), "", "", []string{}, nil).LoadOne(minioId)
	if s.Err != "" {
		m.Ctx.Output.SetStatus(400)
		m.Data["json"] = map[string]interface{}{"error": " Could not load the storage resource with id " + minioId + ": " + s.Err}
		m.ServeJSON()
		return "","", false
	}

	live := findLiveStorage(minioId, peerID)
	if live == nil {
		m.Ctx.Output.SetStatus(404)
		m.Data["json"] = map[string]interface{}{"error": "could not find the Minio instance " + s.Err}
		m.ServeJSON()
		return "", "", false
	}

	url := live.Source
	service := infrastructure.NewMinioService(url)

	// call the method ctrating the svcacc
	err := service.CreateClient()
	if err != nil {
		m.Ctx.Output.SetStatus(500)
		m.Data["json"] = map[string]interface{}{"error": "could not create the client for " + minioId + " : " + err.Error()}
		m.ServeJSON()
		return "", "", false
	}

	access, secret, err := service.CreateCredentials(executionsId)
	if err != nil {
		m.Ctx.Output.SetStatus(500)
		m.Data["json"] = map[string]interface{}{"error": "could not create the service account for " + minioId + " : " + err.Error()}
		m.ServeJSON()
		return "", "", false
	}

	err = service.CreateBucket(executionsId)
	if err != nil {
		m.Ctx.Output.SetStatus(500)
		m.Data["json"] = map[string]interface{}{"error": "error while creating the service account for " + minioId + " : " + err.Error()}
		m.ServeJSON()
		return "", "", false
	}
	return access, secret, true
}

func findLiveStorage(storageId string, peerId string) *live.LiveStorage {
	res := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_STORAGE),"",peerId,[]string{},nil).LoadAll(false)
	if res.Err != "" {
		l := oclib.GetLogger()
		l.Error().Msg(res.Err)
		return nil
	}

	for _, dbo := range res.Data {
		r := oclib.NewRequest(oclib.LibDataEnum(oclib.LIVE_STORAGE),"","",[]string{},nil).LoadOne(dbo.GetID())
		l := r.ToLiveStorage()
		for _, id := range l.ResourcesID {
			if id == storageId {
				return l
			}
		}
	}

	return nil
}