package file_download

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/log"
	"go.uber.org/zap"

	apierr "github.com/pingcap-inc/clinic/pkg/api/error"
	"github.com/pingcap-inc/clinic/pkg/ngm/file_download/api"
)

const ExternalDownloadPathContextKey = "external_ngm_download_path"

// const (
// 	DefaultTimeout = time.Second * 10
// )

type Service struct {
	Query api.Query
}

func (s *Service) ListFileGinHandler(c *gin.Context) {
	param := &ListFileParam{}
	param.Provider = c.GetHeader("X-Provider")
	param.Region = c.GetHeader("X-Region")
	param.OrgID = c.GetHeader("X-Org-Id")
	param.ProjectID = c.GetHeader("X-Project-Id")
	param.ClusterID = c.GetHeader("X-Cluster-Id")
	param.Instances = c.Query("instances")
	startTs, err := strconv.ParseInt(c.Query("start"), 10, 64)
	if err != nil {
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}
	endTs, err := strconv.ParseInt(c.Query("end"), 10, 64)
	if err != nil {
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}

	param.StartUnixSec = startTs
	param.EndUnixSec = endTs
	if err = param.Validate(); err != nil {
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}

	// ctx, cancel := context.WithTimeout(c.Request.Context(), DefaultTimeout)
	// defer cancel()

	data, err := s.Query.List(c.Request.Context(), &api.ListParam{
		Provider:     param.Provider,
		Region:       param.Region,
		OrgID:        param.OrgID,
		ProjectID:    param.ProjectID,
		ClusterID:    param.ClusterID,
		Instances:    param.Instances,
		StartUnixSec: param.StartUnixSec,
		EndUnixSec:   param.EndUnixSec,
	})
	if err != nil {
		log.Warn("failed to list file", zap.Error(err))
		_ = c.Error(err)
		return
	}
	if downloadPath, ok := c.Get(ExternalDownloadPathContextKey); ok {
		if externalDownloadPath, ok := downloadPath.(string); ok && externalDownloadPath != "" {
			rewriteDownloadPaths(data, externalDownloadPath)
		}
	}
	c.PureJSON(http.StatusOK, data)
}

func rewriteDownloadPaths(data *api.ListData, externalDownloadPath string) {
	for recordIndex := range data.Records {
		for fileIndex := range data.Records[recordIndex].Files {
			file := &data.Records[recordIndex].Files[fileIndex]
			query := ""
			if separator := strings.IndexByte(file.DownloadPath, '?'); separator >= 0 {
				query = file.DownloadPath[separator:]
			}
			file.DownloadPath = externalDownloadPath + query
			file.DownloadURL = externalDownloadPath + query
		}
	}
}

func (s *Service) DownloadGinHandler(c *gin.Context) {
	param := &DownloadFileParam{}
	param.Key = c.Query("key")
	param.Provider = c.Query("provider")
	param.Region = c.Query("region")

	if err := param.Validate(); err != nil {
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}

	// ctx, cancel := context.WithTimeout(c.Request.Context(), DefaultTimeout)
	// defer cancel()

	data, err := s.Query.Download(c.Request.Context(), &api.DownloadParam{
		Provider: param.Provider,
		Region:   param.Region,
		Key:      param.Key,
	})
	if err != nil {
		log.Warn("failed to download file", zap.Error(err))
		_ = c.Error(err)
		return
	}
	c.DataFromReader(http.StatusOK, data.ContentLength, data.ContentType, data.Reader, data.Headers)
	_ = data.Close()
}
