package daemons

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"oc-schedulerd/conf"

	"github.com/rs/zerolog"
)

type ContainerMonitor struct {
	Monitor 	LocalMonitor
	KubeCA		string
	KubeCert	string
	KubeData	string
	KubeHost	string
	KubePort	string
}

func NewContainerMonitor(executionsId string, peerId string, duration int) (Executor){
	return &ContainerMonitor{
		Monitor: LocalMonitor{	
			ExecutionID: executionsId,
			PeerID: peerId,
			Duration: duration,
			LokiUrl: conf.GetConfig().LokiUrl,
			MongoUrl: conf.GetConfig().MongoUrl,
			DBName: conf.GetConfig().DBName,
		},
		KubeCA: conf.GetConfig().KubeCA,
		KubeCert: conf.GetConfig().KubeCert,
		KubeData: conf.GetConfig().KubeData,
		KubeHost: conf.GetConfig().KubeHost,
		KubePort: conf.GetConfig().KubePort,
	}
}

func (cm *ContainerMonitor) PrepareMonitorExec() []string { 

	args := []string{
		"-e", cm.Monitor.ExecutionID,
		"-p", cm.Monitor.PeerID,
		"-u", cm.Monitor.LokiUrl,
		"-m", cm.Monitor.MongoUrl,
		"-d", cm.Monitor.DBName,
		"-M", "kubernetes",
		"-H", cm.KubeHost,
		"-P", cm.KubePort,
		"-C", cm.KubeCert, 
		"-D", cm.KubeData,
		"-c", cm.KubeCA,
	}

	if cm.Monitor.Duration > 0 {
		args = append(args, "-t", fmt.Sprintf("%d", cm.Monitor.Duration))
	}

	return args 
	
}

// Contact the docker's API at the KubeHost's URL to :
// - Check if the image exists
// - Create the container
// - Start the container
func (cm *ContainerMonitor) LaunchMonitor(args []string, l zerolog.Logger) {
	
	var containerID string 
	imageName := "oc-monitord"
	url := "http://" + cm.KubeHost + ":2375"

	resp, err := http.Get(url + "/images/" + imageName + "/json")
	if err != nil {
		l.Fatal().Msg("Error when contacting the docker API on " + url + ": " + err.Error())
	}

	if resp.StatusCode != http.StatusOK {
		d, _ := io.ReadAll(resp.Body)
		l.Fatal().Msg("Couldn't find the oc-monitord image : " + string(d))
	}
	
	dataCreation := map[string]interface{}{"Image": imageName, "Cmd" : args}
	byteData, err := json.Marshal(dataCreation)
	if err != nil {
		l.Fatal().Msg("Error when contacting the creating request body : " + err.Error())
	}
	
	r, _ := http.NewRequest("POST",url + "/containers/create", bytes.NewBuffer(byteData))
	r.Header.Add("Content-Type","application/json")
	resp, err = http.DefaultClient.Do(r)
	if err != nil {
		l.Fatal().Msg("Error when contacting the docker API on " + url + ": " + err.Error())
	}

	if resp.StatusCode == 201 {
		var d map[string]interface{}

		b, err := io.ReadAll(resp.Body)
		if err != nil {
			l.Fatal().Msg(err.Error())
		}

		err = json.Unmarshal(b, &d)
		if err != nil {
			l.Fatal().Msg(err.Error())
		}

		containerID = d["Id"].(string)
	} else {
		d, _ := io.ReadAll(resp.Body)
		l.Fatal().Msg("Error when creating the container on " + url + "\n " + string(d))
	}

	networkName := "oc"

	dataNetwork, _ := json.Marshal(map[string]string{"Container" : containerID})
	r, _ = http.NewRequest("POST",url + "/networks/" + networkName + "/connect", bytes.NewBuffer(dataNetwork))
	r.Header.Add("Content-Type","application/json")
	resp, err = http.DefaultClient.Do(r)
	if err != nil {
		l.Fatal().Msg("Error when contacting the docker API on " + url + ": " + err.Error())
	}
	if resp.StatusCode != 200 {
		d, _ := io.ReadAll(resp.Body)
		l.Error().Msg("Error when adding container to the network : " + string(d))
		return
	}

	resp, err = http.Post( url + "/containers/" + containerID + "/start", "", nil)
	if err != nil {
		l.Fatal().Msg("Error when contacting the docker API on " + url + ": " + err.Error())
	}

	if resp.StatusCode >= 300 {
		d, _ := io.ReadAll(resp.Body)
		l.Fatal().Msg("Error when starting the container on " + url + "\n " + string(d))
	}

	l.Info().Msg("Started container " + containerID)
	// we can add logging with GET /containers/id/logs?stdout=true&follow=true

	// logExecution(stdoutMonitord, l)
}