package server

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

	"github.com/tidbcloud/config-service/api/v1alpha1"
	"github.com/tidbcloud/config-service/sdk/api"
)

func (s *Server) DescribeBackupConfiguration(w http.ResponseWriter, r *http.Request) {
	s.describeBRConfiguration(w, r, func(cc *v1alpha1.ClusterConfig) (api.Image, map[string]interface{}, error) {
		image := api.Image{
			BaseImage: cc.Spec.Backup.BaseImage,
			Tag:       cc.Spec.Backup.Tag,
		}
		if cc.Spec.Backup == nil {
			err := fmt.Errorf("no backup config")
			s.log.Error(err, "describe backup configuration")
			return image, nil, err
		}
		return image, cc.Spec.Backup.Config.MP, nil
	})
}

func (s *Server) DescribeRestoreConfiguration(w http.ResponseWriter, r *http.Request) {
	s.describeBRConfiguration(w, r, func(cc *v1alpha1.ClusterConfig) (api.Image, map[string]interface{}, error) {
		image := api.Image{
			BaseImage: cc.Spec.Restore.BaseImage,
			Tag:       cc.Spec.Restore.Tag,
		}
		if cc.Spec.Restore == nil {
			err := fmt.Errorf("no restore config")
			s.log.Error(err, "describe restore configuration")
			return image, nil, err
		}
		return image, cc.Spec.Restore.Config.MP, nil
	})
}

func (s *Server) describeBRConfiguration(w http.ResponseWriter, r *http.Request, toConfig func(cc *v1alpha1.ClusterConfig) (api.Image, map[string]interface{}, error)) {
	var input api.DescribeBRConfigInput

	err := json.NewDecoder(r.Body).Decode(&input)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	err = validateDescriberBRConfigInput(input)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	cc, err := s.findAndValidateClusterConfig(input.TenantID, input.ClusterID)
	if err != nil {
		s.log.Error(err, "find cluster config", input)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	output, err := generateBRConfigOutput(cc, toConfig)
	if err != nil {
		s.log.Error(err, "generate br Config output", input)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = json.NewEncoder(w).Encode(output)
	if err != nil {
		s.log.Error(err, "encoder cluster config", input)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
}

func validateDescriberBRConfigInput(input api.DescribeBRConfigInput) error {
	if input.TenantID == nil {
		return fmt.Errorf("must specipy tenant ID")
	}
	return nil
}

func generateBRConfigOutput(cc *v1alpha1.ClusterConfig, toConfig func(cc *v1alpha1.ClusterConfig) (api.Image, map[string]interface{}, error)) (*api.DescribeBRConfigOutput, error) {
	image, mp, err := toConfig(cc)
	if err != nil {
		return nil, err
	}

	output := api.DescribeBRConfigOutput{
		Version: cc.Spec.Version,
		Image:   image,
		ConfigMeta: &api.ConfigMeta{
			ID:            cc.ObjectMeta.Name,
			GitCommitID:   cc.Spec.ConfigMeta.GitCommitID,
			ConfigVersion: cc.Spec.ConfigMeta.ConfigVersion,
		},
		Config: mp,
	}

	return &output, nil
}
