package logic

import (
	"bytes"
	"encoding/json"
	"fusenapi/model/gmodel"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/collect"
	"fusenapi/utils/format"
	"log"
	"strings"
	"text/template"

	"context"

	"fusenapi/server/backend/internal/svc"
	"fusenapi/server/backend/internal/types"

	"github.com/tidwall/gjson"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
)

type QuotationDetailLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewQuotationDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QuotationDetailLogic {
	return &QuotationDetailLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func GetPrice(num int64, stepNum []int64, stepPrice []int64) int64 {
	//阶梯价计算
	if num > stepNum[len(stepNum)-1] {
		return stepPrice[len(stepPrice)-1]
	}
	for k, v := range stepNum {
		if num <= v {
			return stepPrice[k]
		}
	}
	return 0
}

// GetDemoHtml 报价单
func (l *QuotationDetailLogic) GetDemoHtml(quot *gmodel.FsQuotation, quotationProduct []*gmodel.FsQuotationProduct) (htmlcontent string, err error) {

	// htmlContent := ""
	priceHtml := ""
	// productNum := len(quotationProduct)
	// page := 3
	// pageTotal := 3 + productNum

	for _, quotProduct := range quotationProduct {

		var priceInfo []map[string]interface{}
		err := json.Unmarshal([]byte(*quotProduct.PriceInfo), &priceInfo)
		if err != nil {
			return "", err
		}
		priceHtmlTpl := `
	{{range $i, $parr := .priceInfo}} 
		{{if lt $i 3}}
		<div class="pr-card">  
			<p class="pr">${{$parr.price}}</p>  
			<p class="num">{{$parr.num}}<span> Units</span></p>   
		</div>
		{{else}}
		<div class="pr-card" style="margin-right: 8px;">  
			<p class="pr">${{$parr.price}}</p>  
			<p class="num">{{$parr.num}}<span> Units</span></p>
		</div>
		{{end}}
	{{end}}`

		tpl := template.Must(template.New("prCardTpl").Parse(priceHtmlTpl))
		buf := &bytes.Buffer{}
		err = tpl.Execute(buf, map[string]interface{}{
			"priceInfo": priceInfo,
		})
		if err != nil {
			log.Println(err)
			return "", err
		}
		priceHtml = buf.String()
	}

	tpl := template.New("quto")
	tpl = tpl.Funcs(format.TemplateFuncMap)

	tpl = template.Must(tpl.ParseFiles(templatePath + "/products.tpl"))
	buf := &bytes.Buffer{}

	tpl.Execute(buf, map[string]interface{}{
		"products":   collect.StructSliceJson2Maps(quotationProduct),
		"price_html": priceHtml,
	})
	htmlContent := buf.String()
	// log.Println(htmlContent)
	return htmlContent, nil
}

func (l *QuotationDetailLogic) QuotationDetail(req *types.RequestQuotationId, userinfo *auth.BackendUserInfo) (resp *basic.Response) {
	// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
	// userinfo 传入值时, 一定不为null
	quot, err := l.svcCtx.AllModels.FsQuotation.FindOneOnlyById(l.ctx, req.QuotationId)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return resp.SetStatus(basic.CodeDbRecordNotFoundErr)
		}
		return resp.SetStatus(basic.CodeDbSqlErr)
	}

	CanteenProduct, err := l.svcCtx.AllModels.FsCanteenProduct.GetAllByCanteenTypeIdOrderAsc(l.ctx, *quot.CanteenType)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return resp.SetStatus(basic.CodeDbRecordNotFoundErr)
		}
		return resp.SetStatus(basic.CodeDbSqlErr)
	}

	quotationProduct, err := l.svcCtx.AllModels.FsQuotationProduct.GetAllByQuotationIdOrderAsc(l.ctx, req.QuotationId)
	if err != nil {
		if err != gorm.ErrRecordNotFound {
			return resp.SetStatus(basic.CodeDbSqlErr)
		}
	}

	var target any = quotationProduct
	if len(quotationProduct) == 0 {
		target = CanteenProduct
	}

	jdata, err := json.Marshal(target)
	if err != nil {
		logx.Error(err)
		return resp.SetStatus(basic.CodeJsonErr)
	}

	list := gjson.ParseBytes(jdata)

	qFlag := len(quotationProduct) > 0

	//获取备注模板
	// markList, err := l.svcCtx.AllModels.FsQuotationRemarkTemplate.GetAllSelectContent(l.ctx)

	var productIds = collect.ArrayColumnTag[int64](CanteenProduct, "product_id")
	productList, err := l.svcCtx.AllModels.FsProduct.FindAllOnlyByIds(l.ctx, productIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatus(basic.CodeDbSqlErr)
	}
	productListMap := collect.Array2MapByKeyTag[int64](productList, "id")

	//获取size信息
	var sizeIds = collect.ArrayColumnTag[int64](CanteenProduct, "size_id")
	sizes, err := l.svcCtx.AllModels.FsProductSize.GetAllSelectIdAndCapacityByIds(l.ctx, sizeIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatus(basic.CodeDbSqlErr)
	}
	sizesMap := collect.Array2MapByKeyTag[int64](sizes, "id")

	//获取价格信息
	productPrice, err := l.svcCtx.AllModels.FsProductPrice.GetAllSelectBySizeId(l.ctx, sizeIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatus(basic.CodeDbSqlErr)
	}
	productPriceMap := collect.Array2MapByKeyTag[int64](productPrice, "size_id")
	// product := []map[string]interface{}{}

	products := []map[string]interface{}{}
	for _, parr := range list.Array() {

		var priceList []map[string]int64

		if !qFlag {

			if price, ok := productPriceMap[parr.Get("size_id").Int()]; !ok {
				priceList = []map[string]int64{
					{"num": 1, "price": 0},
					{"num": 1, "price": 0},
					{"num": 1, "price": 0},
				}
			} else {

				i := 0
				price.StepNum = collect.ArrayString2Int(strings.Split(price.StepNum.(string), ","))
				price.StepPrice = collect.ArrayString2Int(strings.Split(price.StepPrice.(string), ","))
				for price.MinBuyNum < int64(len(price.StepNum.([]string))+5) && i < 3 {
					priceList = append(priceList, map[string]int64{
						"num":   int64(price.MinBuyNum * price.EachBoxNum),
						"price": GetPrice(price.MinBuyNum, price.StepNum.([]int64), price.StepPrice.([]int64)) / 100,
					})
					price.MinBuyNum++
					i++
				}
				if len(priceList) < 3 {
					for j := 0; j < 3-len(priceList); j++ {
						priceList = append(priceList, map[string]int64{"num": 1, "price": 0})
					}
				}
			}
		}

		var (
			Id        any
			priceInfo any
			mark      any
			sid       any

			isGift bool
			name   any
			size   any
			cycle  any
			img    any

			num any
		)
		if qFlag {

			Id = parr.Get("id")

			err = json.Unmarshal([]byte(parr.Get("price_info").String()), &priceInfo)
			if err != nil {
				logx.Error(err)
				return resp.SetStatus(basic.CodeJsonErr)
			}

			if parr.Get("sid").Exists() {
				sid = parr.Get("sid").Int()
			}

			name = parr.Get("name").String()
			size = parr.Get("size").Int()
			cycle = parr.Get("cycle").Int()
			img = parr.Get("img").String()

			if parr.Get("remark").Exists() {
				err = json.Unmarshal([]byte(parr.Get("remark").String()), &mark)
				if err != nil {
					logx.Error(err)
					return resp.SetStatus(basic.CodeJsonErr)
				}
			}

			num = parr.Get("num").Int()

		} else {

			if parr.Get("sid").Exists() {
				sid = parr.Get("sid").Int()
			}

			product := productListMap[parr.Get("product_id").Int()]
			name = product.Title
			size = sizesMap[parr.Get("size_id").Int()].Capacity
			cycle = *product.ProduceDays + *product.DeliveryDays
			img = ""
			mark = []string{}
			priceInfo = priceList
			num = 1
		}

		products = append(products, map[string]interface{}{
			"id":         Id,
			"s_id":       sid,
			"is_gift":    isGift,
			"name":       name,
			"size":       size,
			"cycle":      cycle,
			"img":        img,
			"mark":       mark,
			"price_list": priceInfo,
			"num":        num,
		})

	}

	htmlContent, err := l.GetDemoHtml(&quot, quotationProduct)
	if err != nil {
		panic(err)
	}
	log.Println(htmlContent)

	saler, err := l.svcCtx.AllModels.FsQuotationSaler.GetOne(l.ctx, quot.Id)
	if err != nil {
		logx.Error(err)
		if err == gorm.ErrRecordNotFound {
			return resp.SetStatus(basic.CodeDbRecordNotFoundErr)
		}
		return resp.SetStatus(basic.CodeDbSqlErr)
	}

	// log.Println(saler)

	tpl := template.New("quto")
	tpl = tpl.Funcs(format.TemplateFuncMap)

	tpl = template.Must(tpl.ParseFiles(templatePath + "/return_html.tpl"))
	buf := &bytes.Buffer{}

	err = tpl.Execute(buf, map[string]interface{}{
		"demoHtml":  htmlContent,
		"qutoInfo":  collect.StructJson2Map(quot),
		"salerInfo": collect.StructJson2Map(saler),
	})
	if err != nil {
		return resp.SetStatus(basic.CodeApiErr)
	}
	// returnHtmlContent := buf.String()

	return resp.SetStatus(basic.CodeOK)
}