package cautils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"

	"github.com/armosec/kubescape/cautils/getter"
	pkgutils "github.com/armosec/utils-go/utils"
)

const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK"

var BuildNumber string

const UnknownBuildNumber = "unknown"

type IVersionCheckHandler interface {
	CheckLatestVersion(*VersionCheckRequest) error
}

func NewIVersionCheckHandler() IVersionCheckHandler {
	if BuildNumber == "" {
		WarningDisplay(os.Stderr, "Warning: unknown build number, this might affect your scan results. Please make sure you are updated to latest version.\n")
	}
	if v, ok := os.LookupEnv(SKIP_VERSION_CHECK); ok && pkgutils.StringToBool(v) {
		return NewVersionCheckHandlerMock()
	}
	return NewVersionCheckHandler()
}

type VersionCheckHandlerMock struct {
}

func NewVersionCheckHandlerMock() *VersionCheckHandlerMock {
	return &VersionCheckHandlerMock{}
}

type VersionCheckHandler struct {
	versionURL string
}
type VersionCheckRequest struct {
	Client           string `json:"client"`           // kubescape
	ClientVersion    string `json:"clientVersion"`    // kubescape version
	Framework        string `json:"framework"`        // framework name
	FrameworkVersion string `json:"frameworkVersion"` // framework version
	ScanningTarget   string `json:"target"`           // scanning target- cluster/yaml
}

type VersionCheckResponse struct {
	Client          string `json:"client"`          // kubescape
	ClientUpdate    string `json:"clientUpdate"`    // kubescape latest version
	Framework       string `json:"framework"`       // framework name
	FrameworkUpdate string `json:"frameworkUpdate"` // framework latest version
	Message         string `json:"message"`         // alert message
}

func NewVersionCheckHandler() *VersionCheckHandler {
	return &VersionCheckHandler{
		versionURL: "https://us-central1-elated-pottery-310110.cloudfunctions.net/ksgf1v1",
	}
}
func NewVersionCheckRequest(buildNumber, frameworkName, frameworkVersion, scanningTarget string) *VersionCheckRequest {
	if buildNumber == "" {
		buildNumber = UnknownBuildNumber
	}
	if scanningTarget == "" {
		scanningTarget = "unknown"
	}
	return &VersionCheckRequest{
		Client:           "kubescape",
		ClientVersion:    buildNumber,
		Framework:        frameworkName,
		FrameworkVersion: frameworkVersion,
		ScanningTarget:   scanningTarget,
	}
}

func (v *VersionCheckHandlerMock) CheckLatestVersion(versionData *VersionCheckRequest) error {
	fmt.Println("Skipping version check")
	return nil
}

func (v *VersionCheckHandler) CheckLatestVersion(versionData *VersionCheckRequest) error {
	defer func() {
		if err := recover(); err != nil {
			WarningDisplay(os.Stderr, "failed to get latest version\n")
		}
	}()

	latestVersion, err := v.getLatestVersion(versionData)
	if err != nil || latestVersion == nil {
		return fmt.Errorf("failed to get latest version")
	}

	if latestVersion.ClientUpdate != "" {
		if BuildNumber != "" && BuildNumber < latestVersion.ClientUpdate {
			WarningDisplay(os.Stderr, warningMessage(latestVersion.Client, latestVersion.ClientUpdate)+"\n")
		}
	}

	// TODO - Enable after supporting framework version
	// if latestVersion.FrameworkUpdate != "" {
	// 	fmt.Println(warningMessage(latestVersion.Framework, latestVersion.FrameworkUpdate))
	// }

	if latestVersion.Message != "" {
		InfoDisplay(os.Stderr, latestVersion.Message+"\n")
	}

	return nil
}

func (v *VersionCheckHandler) getLatestVersion(versionData *VersionCheckRequest) (*VersionCheckResponse, error) {

	reqBody, err := json.Marshal(*versionData)
	if err != nil {
		return nil, fmt.Errorf("in 'CheckLatestVersion' failed to json.Marshal, reason: %s", err.Error())
	}

	resp, err := getter.HttpPost(http.DefaultClient, v.versionURL, map[string]string{"Content-Type": "application/json"}, reqBody)
	if err != nil {
		return nil, err
	}

	vResp := &VersionCheckResponse{}
	if err = getter.JSONDecoder(resp).Decode(vResp); err != nil {
		return nil, err
	}
	return vResp, nil
}

func warningMessage(kind, release string) string {
	return fmt.Sprintf("Warning: '%s' is not updated to the latest release: '%s'", kind, release)
}
