package cloud_billing

import (
	"mime/multipart"
	"net/http"
	"time"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"

	"github.com/pingcap-inc/data-ingestion-tools/internal/itcronjob/service"
	"github.com/pingcap-inc/data-ingestion-tools/internal/itcronjob/store"
	"github.com/pingcap-inc/data-ingestion-tools/model"
	"github.com/pingcap-inc/data-ingestion-tools/pkg/errors"
	"github.com/pingcap-inc/data-ingestion-tools/pkg/log"
	"github.com/pingcap-inc/data-ingestion-tools/pkg/util/ginres"
)

type CloudBillingController struct {
	srv service.Service
}

func NewCloudBillingController(store store.Factory) *CloudBillingController {
	return &CloudBillingController{
		srv: service.NewService(store),
	}
}

type Form struct {
	File *multipart.FileHeader `form:"file" binding:"required"`
}

type AmisResponse struct {
	Status int         `json:"status"`
	Msg    string      `json:"msg"`
	Data   interface{} `json:"data"`
}

// parse upload file
func (cbc *CloudBillingController) Upload(c *gin.Context) {
	var form Form
	if err := c.ShouldBind(&form); err != nil {
		c.JSON(400, gin.H{
			"error": "file not found",
		})
		return
	}
	// params
	cloudProvider := c.Query("cloud_provider")
	if cloudProvider == "" {
		c.JSON(400, gin.H{
			"error": "cloud provider is empty",
		})

		return
	}
	log.L(c).Infof("cloud provider: %s", cloudProvider)

	month := c.Query("month")
	if month == "" {
		c.JSON(400, gin.H{
			"error": "month is empty",
		})
		return
	}

	session := sessions.Default(c)
	user := session.Get("email").(string)
	err := cbc.srv.CloudBilling().ParseBillingFile(c, user, cloudProvider, month, form.File)
	if err != nil {
		c.JSON(500, gin.H{
			"error": err.Error(),
		})

		return
	}

	c.JSON(http.StatusOK, AmisResponse{
		Msg: "upload success",
	})
}

func (cbc *CloudBillingController) Download(c *gin.Context) {
	log.L(c).Infof("start download cloud billing")

	var list model.CloudBillingList

	// get params
	if err := c.ShouldBindQuery(&list); err != nil {
		ginres.WriteResponse(c, errors.New("params error"), nil)
		return
	}

	// file name
	fileName := ""

	if list.PageType == service.OVERSEA {
		fileName = "oversea"
	} else if list.PageType == service.DOMESTIC {
		fileName = "domestic"
	} else if list.PageType == service.ACCOUNTS {
		fileName = "account"
	}

	if list.CloudProvider != "" {
		fileName = fileName + "-" + list.CloudProvider
	}
	if list.Month != "" {
		fileName = fileName + "-" + list.Month
	} else {
		c.JSON(400, gin.H{
			"error": "month is empty",
		})

		return
	}

	fileName = fileName + ".xlsx"

	filePath, err := cbc.srv.CloudBilling().Download(c, list, fileName)
	if err != nil {
		ginres.WriteResponse(c, err, nil)

		return
	}
	go ginres.WriteResponse(c, nil, "start generate cloud billing")

	// return file
	c.Writer.Header().Add("Content-Disposition", `attachment; filename="`+fileName+`"`)
	c.Writer.Header().Add("Content-Type", "application/octet-stream")
	c.File(filePath)

}

func (cbc *CloudBillingController) GetCloudBillingList(c *gin.Context) {
	log.L(c).Infof("start get cloud billing list")

	var list model.CloudBillingList

	// get params
	if err := c.ShouldBindQuery(&list); err != nil {
		ginres.WriteResponse(c, errors.New("params error"), nil)
		return
	}

	// page is null
	if list.Page == 0 {
		list.Page = 1
	}
	if list.PageSize == 0 {
		list.PageSize = 10
	}
	if list.Month == "" {
		list.Month = latMonth()
	}

	data, err := cbc.srv.CloudBilling().GetCloudBillingList(c, list)
	if err != nil {
		ginres.WriteResponse(c, err, nil)
		return
	}

	ginres.WriteResponse(c, nil, data)

	log.L(c).Infof("end get cloud billing list")
}

func latMonth() string {
	month := time.Now().AddDate(0, -1, 0).Format("2006-01")
	return month
}
