package handler

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"time"
	queries "vctp/db/queries"
	models "vctp/server/models"
)

// VmCreate receives the CloudEvent for a VM creation
func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) {
	var (
		unixTimestamp int64
		//numVcpus      int32
		//numRam        int32
		//datacenter    string
	)

	reqBody, err := io.ReadAll(r.Body)
	if err != nil {
		h.Logger.Error("Invalid data received", "error", err)
		fmt.Fprintf(w, "Invalid data received")
		w.WriteHeader(http.StatusInternalServerError)
		return
	} else {
		h.Logger.Debug("received input data", "length", len(reqBody))
	}

	// Decode the JSON body into CloudEventReceived struct
	var event models.CloudEventReceived
	if err := json.Unmarshal(reqBody, &event); err != nil {
		h.Logger.Error("unable to decode json", "error", err)
		http.Error(w, "Invalid JSON body", http.StatusBadRequest)
		return
	} else {
		h.Logger.Debug("successfully decoded JSON")
		//prettyPrint(event)
	}

	e := event.CloudEvent.Data

	// Convert vmModel to CreateInventoryParams using the utility function
	//var params queries.CreateInventoryParams
	//db.ConvertToSQLParams(&vm, &params)

	// Parse the datetime string to a time.Time object
	eventTime, err := time.Parse(time.RFC3339, event.CloudEvent.Time)
	if err != nil {
		h.Logger.Warn("unable to convert cloud event time to timestamp", "error", err)
		unixTimestamp = time.Now().Unix()
	} else {
		// Convert to Unix timestamp
		unixTimestamp = eventTime.Unix()
	}

	// Create an instance of CreateInventoryParams
	h.Logger.Debug("Creating database parameters")

	params := queries.CreateEventParams{
		Source:              event.CloudEvent.Source,
		CloudId:             event.CloudEvent.ID,
		EventTime:           sql.NullInt64{Int64: unixTimestamp, Valid: unixTimestamp > 0},
		ChainId:             strconv.Itoa(e.ChainID),
		VmId:                sql.NullString{String: e.VM.VM.Value, Valid: e.VM.VM.Value != ""},
		VmName:              sql.NullString{String: e.VM.Name, Valid: e.VM.Name != ""},
		EventKey:            sql.NullString{String: strconv.Itoa(e.Key), Valid: strconv.Itoa(e.Key) != ""},
		DatacenterName:      sql.NullString{String: e.Datacenter.Name, Valid: e.Datacenter.Name != ""},
		DatacenterId:        sql.NullString{String: e.Datacenter.Datacenter.Value, Valid: e.Datacenter.Datacenter.Value != ""},
		ComputeResourceName: sql.NullString{String: e.ComputeResource.Name, Valid: e.ComputeResource.Name != ""},
		ComputeResourceId:   sql.NullString{String: e.ComputeResource.ComputeResource.Value, Valid: e.ComputeResource.ComputeResource.Value != ""},
		UserName:            sql.NullString{String: e.UserName, Valid: e.UserName != ""},
	}

	h.Logger.Debug("database params", "params", params)

	// Insert the new inventory record into the database
	result, err := h.Database.Queries().CreateEvent(context.Background(), params)
	if err != nil {
		h.Logger.Error("unable to perform database insert", "error", err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error : %v\n", err)
		return
	} else {
		h.Logger.Debug("created database record", "insert_result", result)
	}

	//h.Logger.Debug("received create request", "body", string(reqBody))
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "Create Request : %v\n", result)
}

// prettyPrint comes from https://gist.github.com/sfate/9d45f6c5405dc4c9bf63bf95fe6d1a7c
func prettyPrint(args ...interface{}) {
	var caller string

	timeNow := time.Now().Format("01-02-2006 15:04:05")
	prefix := fmt.Sprintf("[%s] %s -- ", "PrettyPrint", timeNow)
	_, fileName, fileLine, ok := runtime.Caller(1)

	if ok {
		caller = fmt.Sprintf("%s:%d", fileName, fileLine)
	} else {
		caller = ""
	}

	fmt.Printf("\n%s%s\n", prefix, caller)

	if len(args) == 2 {
		label := args[0]
		value := args[1]

		s, _ := json.MarshalIndent(value, "", "\t")
		fmt.Printf("%s%s: %s\n", prefix, label, string(s))
	} else {
		s, _ := json.MarshalIndent(args, "", "\t")
		fmt.Printf("%s%s\n", prefix, string(s))
	}
}
