package retool

import (
	"finance-portal/pkg/util/ginres"
	"github.com/gin-gonic/gin"

	"finance-portal/internal/dataplatform/service"
	"finance-portal/internal/dataplatform/store"
	"finance-portal/model"
	"finance-portal/pkg/log"
)

type RetoController struct {
	srv service.Service
}

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

func (s *RetoController) Reto(c *gin.Context) {
	log.L(c).Infof("start sync retool to bq")
	c.JSON(500, gin.H{
		"data": map[string]interface{}{
			"code": 500,
			"msg":  "start sync retool to bq",
		},
	})
}

func (s *RetoController) SalesforceSingle(c *gin.Context) {
	log.L(c).Infof("start sync salesforce single")

	var req model.SfReqBody
	if err := c.ShouldBindJSON(&req); err != nil {
		log.L(c).Errorf("bind request error: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "bind request error",
			},
		})
		return
	}

	if req.Type == 0 || req.ID == 0 {
		log.L(c).Errorf("request type is empty or id is empty")
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "request type is empty or id is empty",
			},
		})
		return
	}

	req.Types = typeMap(req.Type)

	go s.srv.Salesforce().HandleSingleSF(c, req)

	c.JSON(200, gin.H{
		"msg": "sync select record to salesforce",
	})
}

func (s *RetoController) SalesforceSingleSync(c *gin.Context) {
	log.L(c).Infof("start sync salesforce single synchronously")

	var req model.SfReqBody
	if err := c.ShouldBindJSON(&req); err != nil {
		log.L(c).Errorf("bind request error: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "bind request error",
			},
		})
		return
	}

	if req.Type == 0 || req.ID == 0 {
		log.L(c).Errorf("request type is empty or id is empty")
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "request type is empty or id is empty",
			},
		})
		return
	}

	req.Types = typeMap(req.Type)
	result, err := s.srv.Salesforce().SyncSingleSF(c, req)
	if err != nil {
		log.L(c).Errorf("sync salesforce single failed: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code":   500,
				"msg":    err.Error(),
				"result": result,
			},
		})
		return
	}

	c.JSON(200, gin.H{
		"data": result,
	})
}

func (s *RetoController) SalesforceLastInvoiceMonth(c *gin.Context) {
	log.L(c).Infof("start sync salesforce last invoice month")

	var req model.SfReqBody
	if err := c.ShouldBindJSON(&req); err != nil {
		log.L(c).Errorf("bind request error: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "bind request error",
			},
		})
		return
	}

	if req.Type == 0 {
		log.L(c).Errorf("request type is empty")
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "request type is empty",
			},
		})
		return
	}
	if err := req.ValidateLastMonthBatchScope(); err != nil {
		log.L(c).Errorf("invalid last invoice month batch scope: %v", err)
		c.JSON(400, gin.H{
			"data": map[string]interface{}{
				"code": 400,
				"msg":  err.Error(),
			},
		})
		return
	}

	req.Types = typeMap(req.Type)

	go s.srv.Salesforce().HandleLastInvoiceMonthSF(c, req)

	response := gin.H{
		"msg": "start sync last invoice month records to salesforce",
	}
	if req.Limit > 0 || len(req.OrderIDs) > 0 {
		response["batch"] = gin.H{
			"limit":     req.Limit,
			"order_ids": req.OrderIDs,
		}
	}
	c.JSON(200, response)
}

func (s *RetoController) ARTable(c *gin.Context) {
	log.L(c).Info("start deal ar table")

	go s.srv.Cloud().HandleARTable(c)

	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "start deal ar table",
	})
}

func (s *RetoController) GenerateCloudBreakdown(c *gin.Context) {
	log.L(c).Info("start generate cloud breakdown")

	go s.srv.Cloud().HandleCloudBreakdown(c)

	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "start generate cloud revrec",
	})
}

func (s *RetoController) Download(c *gin.Context) {
	log.L(c).Info("start download")

	var req model.SfReqBody
	if err := c.ShouldBindJSON(&req); err != nil {
		log.L(c).Errorf("bind request error: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "bind request error",
			},
		})
		return
	}

	if req.Type == 0 {
		log.L(c).Errorf("request type is empty ")
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "request type is empty ",
			},
		})
		return
	}

	req.Types = typeMap(req.Type)

	buf, err := s.srv.Cloud().HandleDownload(c, req)
	if err != nil {
		log.L(c).Errorf("download failed: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "download failed: " + err.Error(),
			},
		})
		return
	}

	fname := req.Types + "_" + req.BillMonth + ".csv"

	c.Writer.Header().Set("Content-Type", "text/csv")
	c.Writer.Header().Set("Content-Disposition", "attachment; filename="+fname)
	c.Writer.WriteHeader(200)
	_, _ = c.Writer.Write(buf.Bytes())
}

func (s *RetoController) Upload(c *gin.Context) {
	log.L(c).Info("start upload invoice")

	var req model.UploadBody
	if err := c.ShouldBindJSON(&req); err != nil {
		log.L(c).Errorf("bind request error: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "bind request error",
			},
		})
		return
	}

	if req.ID == "" || len(req.Files) == 0 {
		log.L(c).Errorf("request id or invoice is empty")
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "request id or invoice is empty",
			},
		})
		return
	}

	err := s.srv.Cloud().HandleUpload(c, req)

	if err != nil {
		log.L(c).Errorf("upload invoice failed: %v", err)
		c.JSON(500, gin.H{
			"data": map[string]interface{}{
				"code": 500,
				"msg":  "upload invoice failed: " + err.Error(),
			},
		})
		return
	}

	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "upload invoice success",
	})

}

func (sfc *RetoController) EventCenter(c *gin.Context) {
	log.L(c).Infof("handle ps man days reject")

	// parse params

	etype, ok := c.GetQuery("type")
	if etype == "" || !ok {
		ginres.WriteResponse(c, nil, "type is empty")

		return
	}

	go sfc.srv.Salesforce().EventCenter(c, etype)

	ginres.WriteResponse(c, nil, "start sync to salesforce")
}

func (s *RetoController) Fix(c *gin.Context) {
	log.L(c).Info("start fix")
	s.srv.Salesforce().Fix(c)
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "start fix",
	})
}

func typeMap(typ int) string {
	switch typ {
	case 1:
		return "order"
	case 2:
		return "revrec"
	case 3:
		return "collection"
	case 4:
		return "ar"
	case 5:
		return "mk_collection"
	case 6:
		return "pb_collection"
	case 7:
		return "ns_revrec"
	case 8:
		return "invoice"
	case 9:
		return "exam"
	default:
		return ""
	}
}
