package test_data

import (
	"gitee.com/golang-module/carbon/v2"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
	"math"
	"sort"
	"strconv"
	"testData/global"
	"testData/model"
	"testData/request"
)

func PackagePassProbabilityLine(r *request.PackagePassProbabilityLine) ([]*model.Line, int, int) {
	var sql string
	if r.OrderDateStart != "" && r.OrderDateEnd != "" {
		sql += "tc_sfc02 BETWEEN DATE '" + r.OrderDateStart + "' AND DATE '" + r.OrderDateEnd + "'"
	}
	//else if r.OrderDateStart != "" && r.OrderDateEnd == "" {
	//	sql += "tc_sfc02 >= DATE '" + r.OrderDateStart + "'"
	//} else if r.OrderDateStart == "" && r.OrderDateEnd != "" {
	//	sql += "tc_sfc02 <= DATE '" + r.OrderDateEnd + "'"
	//}
	var factories, x []string
	if len(r.Factory) == 0 {
		global.Oracle.Model(&model.TcSfcFile{}).Where("tc_sfc08 LIKE ?", "%AB%").Where(sql).
			Group("tc_sfc04").Select("tc_sfc04").Find(&factories)
	} else {
		factories = r.Factory
	}
	productMap := make(map[string]int)
	for _, product := range r.Product {
		productMap[product] = 1
	}
	lotMap := make(map[string]int)
	for _, lot := range r.Lot {
		lotMap[lot] = 1
	}
	specificationMap := make(map[string]int)
	for _, specification := range r.Package {
		specificationMap[specification] = 1
	}
	if r.DateSize == "天" {
		days := int(carbon.Parse(r.OrderDateStart).DiffAbsInDays(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < days; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddDays(i).Format("Y-m-d"))
		}
	} else if r.DateSize == "周" {
		weeks := int(carbon.Parse(r.OrderDateStart).DiffAbsInWeeks(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < weeks; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddWeeks(i).Format("Y-m-d"))
		}
	} else if r.DateSize == "月" {
		months := int(carbon.Parse(r.OrderDateStart).DiffAbsInMonths(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < months; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddMonths(i).Format("Y-m"))
		}
	} else if r.DateSize == "年" {
		years := int(carbon.Parse(r.OrderDateStart).DiffAbsInYears(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < years; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddYears(i).Format("Y"))
		}
	}
	max := math.MinInt
	min := math.MaxInt
	var line []*model.Line
	for _, factory := range factories {
		var tcSfcFile []*model.TcSfcFile
		global.Oracle.Where("tc_sfc08 LIKE ? AND tc_sfc04 = ?", "%AB%", factory).Where(sql).
			Preload("PmcFile").
			Preload("TcSfdFile", func(db *gorm.DB) *gorm.DB {
				return db.Preload("ImaFile").Preload("RvaFile", func(db *gorm.DB) *gorm.DB {
					return db.Preload("IddFile")
				})
			}).Preload("TcSfeFile", func(db *gorm.DB) *gorm.DB {
			return db.Preload("ImaFile")
		}).Order("tc_sfc02").Find(&tcSfcFile)
		quantityMap := make(map[string][]float64)
		var y []string
		for _, tcSfc := range tcSfcFile {
			for _, tcSfd := range tcSfc.TcSfdFile {
				if _, ok := productMap[tcSfd.ImaFile.Ima02]; !ok && len(productMap) > 0 {
					continue
				}
				if _, ok := specificationMap[tcSfd.ImaFile.Ima021]; !ok && len(specificationMap) > 0 {
					continue
				}
				var stockInQuantity, failQuantity float64
				for _, rva := range tcSfd.RvaFile {
					for _, idd := range rva.IddFile {
						if _, ok := lotMap[idd.Idd04]; !ok && len(lotMap) > 0 {
							continue
						}
						stockInQuantity += idd.Idd13
						if idd.Idd06 == "BIN99" {
							failQuantity += idd.Idd13
						}
					}
				}
				var s string
				if r.DateSize == "天" {
					s = carbon.Parse(r.OrderDateStart).AddDays(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInDays(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y-m-d")
				} else if r.DateSize == "周" {
					s = carbon.Parse(r.OrderDateStart).AddWeeks(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInWeeks(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y-m-d")
				} else if r.DateSize == "月" {
					s = carbon.Parse(r.OrderDateStart).AddMonths(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInMonths(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y-m")
				} else if r.DateSize == "年" {
					s = carbon.Parse(r.OrderDateStart).AddYears(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInYears(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y")
				}
				if _, ok := quantityMap[s]; !ok {
					quantityMap[s] = []float64{stockInQuantity - failQuantity, stockInQuantity}
				} else {
					quantityMap[s][0] += stockInQuantity - failQuantity
					quantityMap[s][1] += stockInQuantity
				}
			}
		}

		for _, xDate := range x {
			if _, ok := quantityMap[xDate]; ok {
				if quantityMap[xDate][1] == 0 {
					y = append(y, "")
				} else {
					passProbability := decimal.NewFromFloat(quantityMap[xDate][0]).Div(decimal.NewFromFloat(quantityMap[xDate][1])).
						Round(4).Mul(decimal.NewFromFloat(100))

					passProbabilityInt, _ := strconv.Atoi(passProbability.Round(0).String())
					if passProbabilityInt > max {
						max = passProbabilityInt + 1
					}
					if passProbabilityInt < min {
						min = passProbabilityInt - 1
					}
					y = append(y, passProbability.String())
				}
			} else {
				y = append(y, "")
			}
		}
		line = append(line, &model.Line{
			Name: factory,
			X:    x,
			Y:    y,
		})
	}
	return line, max, min
}

func OrderNumberHistogram(r *request.PackagePassProbabilityLine) []*model.Histogram {
	var fTHistogram []*model.Histogram
	var sql string
	if r.OrderDateStart != "" && r.OrderDateEnd != "" {
		sql += "tc_sfc02 BETWEEN DATE '" + r.OrderDateStart + "' AND DATE '" + r.OrderDateEnd + "'"
	}
	//else if r.OrderDateStart != "" && r.OrderDateEnd == "" {
	//	sql += "tc_sfc02 >= DATE '" + r.OrderDateStart + "'"
	//} else if r.OrderDateStart == "" && r.OrderDateEnd != "" {
	//	sql += "tc_sfc02 <= DATE '" + r.OrderDateEnd + "'"
	//}
	var factories, x []string
	if len(r.Factory) == 0 {
		global.Oracle.Model(&model.TcSfcFile{}).Where("tc_sfc08 LIKE ?", "%AB%").Where(sql).
			Group("tc_sfc04").Select("tc_sfc04").Find(&factories)
	} else {
		factories = r.Factory
	}
	productMap := make(map[string]int)
	for _, product := range r.Product {
		productMap[product] = 1
	}
	lotMap := make(map[string]int)
	for _, lot := range r.Lot {
		lotMap[lot] = 1
	}
	specificationMap := make(map[string]int)
	for _, specification := range r.Package {
		specificationMap[specification] = 1
	}
	if r.DateSize == "天" {
		days := int(carbon.Parse(r.OrderDateStart).DiffAbsInDays(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < days; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddDays(i).Format("Y-m-d"))
		}
	} else if r.DateSize == "周" {
		weeks := int(carbon.Parse(r.OrderDateStart).DiffAbsInWeeks(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < weeks; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddWeeks(i).Format("Y-m-d"))
		}
	} else if r.DateSize == "月" {
		months := int(carbon.Parse(r.OrderDateStart).DiffAbsInMonths(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < months; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddMonths(i).Format("m"))
		}
	} else if r.DateSize == "年" {
		years := int(carbon.Parse(r.OrderDateStart).DiffAbsInYears(carbon.Parse(r.OrderDateEnd))) + 1
		for i := 0; i < years; i++ {
			x = append(x, carbon.Parse(r.OrderDateStart).AddYears(i).Format("Y"))
		}
	}
	for _, factory := range factories {
		var tcSfcFile []*model.TcSfcFile
		global.Oracle.Where("tc_sfc08 LIKE ? AND tc_sfc04 = ?", "%AB%", factory).Where(sql).
			Preload("PmcFile").
			Preload("TcSfdFile", func(db *gorm.DB) *gorm.DB {
				return db.Preload("ImaFile").Preload("RvaFile", func(db *gorm.DB) *gorm.DB {
					return db.Preload("IddFile")
				})
			}).Preload("TcSfeFile", func(db *gorm.DB) *gorm.DB {
			return db.Preload("ImaFile")
		}).Order("tc_sfc02").Find(&tcSfcFile)
		quantityMap := make(map[string]float64)
		var y []string
		for _, tcSfc := range tcSfcFile {
			for _, tcSfd := range tcSfc.TcSfdFile {
				if _, ok := productMap[tcSfd.ImaFile.Ima02]; !ok && len(productMap) > 0 {
					continue
				}
				if _, ok := specificationMap[tcSfd.ImaFile.Ima021]; !ok && len(specificationMap) > 0 {
					continue
				}
				var stockInQuantity float64
				for _, rva := range tcSfd.RvaFile {
					for _, idd := range rva.IddFile {
						if _, ok := lotMap[idd.Idd04]; !ok && len(lotMap) > 0 {
							continue
						}
						stockInQuantity += idd.Idd13
					}
				}
				var s string
				if r.DateSize == "天" {
					s = carbon.Parse(r.OrderDateStart).AddDays(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInDays(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y-m-d")
				} else if r.DateSize == "周" {
					s = carbon.Parse(r.OrderDateStart).AddWeeks(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInWeeks(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y-m-d")
				} else if r.DateSize == "月" {
					s = carbon.Parse(r.OrderDateStart).AddMonths(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInMonths(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("m")
				} else if r.DateSize == "年" {
					s = carbon.Parse(r.OrderDateStart).AddYears(int(carbon.Parse(r.OrderDateStart).
						DiffAbsInYears(carbon.CreateFromStdTime(tcSfc.TcSfc02)))).Format("Y")
				}
				if _, ok := quantityMap[s]; !ok {
					quantityMap[s] = stockInQuantity
				} else {
					quantityMap[s] += stockInQuantity
				}
			}
		}

		for _, xDate := range x {
			if _, ok := quantityMap[xDate]; ok {
				y = append(y, decimal.NewFromFloat(quantityMap[xDate]).String())
			} else {
				y = append(y, "0")
			}
		}
		fTHistogram = append(fTHistogram, &model.Histogram{
			Field: factory,
			X:     x,
			Y:     y,
		})
	}
	return fTHistogram
}

func PassProbabilityByFactory(r *request.PassProbabilityByFactory) ([]*model.Line, []*model.Histogram, int, int) {
	var lines []*model.Line
	var histogram []*model.Histogram
	max := math.MinInt
	min := math.MaxInt
	startDate := carbon.Now().SubYear().StartOfMonth().Format("Y-m-d")
	endDate := carbon.Now().EndOfMonth().Format("Y-m-d")
	var factorys []string
	var sql string
	if r.Factory != "" {
		sql += "factory = '" + r.Factory + "'"
	}
	global.PostGreSQL.Model(&model.Report{}).Where("step = ? AND order_date BETWEEN ? AND ?", r.Type, startDate, endDate).
		Where(sql).Group("factory").Select("Factory").Find(&factorys)
	for _, factory := range factorys {
		var x, lineY, histogramY []string
		var reports []*model.Report
		global.PostGreSQL.Where("step = ? AND factory = ? AND order_date BETWEEN ? AND ?", r.Type, factory, startDate, endDate).
			Find(&reports)
		factoryMap := make(map[string][]string)
		for _, report := range reports {
			if _, ok := factoryMap[report.OrderDate[:7]]; !ok {
				factoryMap[report.OrderDate[:7]] = []string{report.TestQuantity, report.PassQuantity}
			} else {
				factoryMapTestQuantity, _ := decimal.NewFromString(factoryMap[report.OrderDate[:7]][0])
				factoryMapPassQuantity, _ := decimal.NewFromString(factoryMap[report.OrderDate[:7]][1])
				testQuantity, _ := decimal.NewFromString(report.TestQuantity)
				passQuantity, _ := decimal.NewFromString(report.PassQuantity)
				factoryMap[report.OrderDate[:7]] = []string{factoryMapTestQuantity.Add(testQuantity).String(),
					factoryMapPassQuantity.Add(passQuantity).String()}
			}
		}
		month := carbon.Now().SubYear().StartOfMonth().Format("Y-m")
		for {
			if month == carbon.Now().EndOfMonth().Format("Y-m") {
				break
			}
			x = append(x, month)
			if _, ok := factoryMap[month]; !ok {
				lineY = append(lineY, "")
				histogramY = append(histogramY, "")
			} else {
				testQuantity, _ := decimal.NewFromString(factoryMap[month][0])
				passQuantity, _ := decimal.NewFromString(factoryMap[month][1])
				passProbability := passQuantity.Div(testQuantity).
					Round(4).Mul(decimal.NewFromFloat(100))
				passProbabilityInt, _ := strconv.Atoi(passProbability.Round(0).String())
				if passProbabilityInt > max {
					max = passProbabilityInt + 1
				}
				if passProbabilityInt < min {
					min = passProbabilityInt - 1
				}
				lineY = append(lineY, passProbability.String())
				histogramY = append(histogramY, factoryMap[month][0])
			}
			month = carbon.Parse(month).AddMonth().Format("Y-m")
		}
		lines = append(lines, &model.Line{
			Name: factory,
			X:    x,
			Y:    lineY,
		})
		histogram = append(histogram, &model.Histogram{
			Field: factory,
			X:     x,
			Y:     histogramY,
		})
	}
	return lines, histogram, max, min
}

func FTPassProbabilityByProduct(r *request.PassProbabilityByProduct) (*model.Line, *model.Histogram, *model.Line, *model.Histogram) {
	var line, binLine *model.Line
	var histogram, binHistogram *model.Histogram
	max := math.MinInt
	min := math.MaxInt
	startDate := carbon.Now().SubYear().StartOfMonth().Format("Y-m-d")
	endDate := carbon.Now().EndOfMonth().Format("Y-m-d")
	var sql string
	if r.Factory != "" {
		sql += "factory = '" + r.Factory + "'"
	}
	var reports []*model.Report
	global.PostGreSQL.Where("step = ? AND product = ? AND order_date BETWEEN ? AND ?",
		r.Type, r.Product, startDate, endDate).Preload("BinFail", func(db *gorm.DB) *gorm.DB {
		return db.Where("report_site_id = ?", 0)
	}).Where(sql).Find(&reports)
	productMap := make(map[string][]string)
	binMap := make(map[string]float64)
	var x, lineY, histogramY []string
	for _, report := range reports {
		if _, ok := productMap[report.OrderDate[:7]]; !ok {
			productMap[report.OrderDate[:7]] = []string{report.TestQuantity, report.PassQuantity}
		} else {
			factoryMapTestQuantity, _ := decimal.NewFromString(productMap[report.OrderDate[:7]][0])
			factoryMapPassQuantity, _ := decimal.NewFromString(productMap[report.OrderDate[:7]][1])
			testQuantity, _ := decimal.NewFromString(report.TestQuantity)
			passQuantity, _ := decimal.NewFromString(report.PassQuantity)
			productMap[report.OrderDate[:7]] = []string{factoryMapTestQuantity.Add(testQuantity).String(),
				factoryMapPassQuantity.Add(passQuantity).String()}
		}
		for _, binFail := range report.BinFail {
			if _, ok := binMap[binFail.HardBin]; !ok {
				binMap[binFail.HardBin] = 0
			}
			quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
			quantity, _ := quantityDecimal.Float64()
			binMap[binFail.HardBin] += quantity
		}
	}
	month := carbon.Now().SubYear().StartOfMonth().Format("Y-m")
	var testStr, passStr string
	for {
		if month == carbon.Now().EndOfMonth().Format("Y-m") {
			break
		}
		x = append(x, month)
		if _, ok := productMap[month]; !ok {
			lineY = append(lineY, "")
			histogramY = append(histogramY, "")
		} else {
			testQuantity, _ := decimal.NewFromString(productMap[month][0])
			passQuantity, _ := decimal.NewFromString(productMap[month][1])
			testDecimal, _ := decimal.NewFromString(testStr)
			passDecimal, _ := decimal.NewFromString(passStr)
			testStr = testDecimal.Add(testQuantity).String()
			passStr = passDecimal.Add(passQuantity).String()
			passProbability := passQuantity.Div(testQuantity).
				Round(4).Mul(decimal.NewFromFloat(100))
			passProbabilityInt, _ := strconv.Atoi(passProbability.Round(0).String())
			if passProbabilityInt > max {
				max = passProbabilityInt + 1
			}
			if passProbabilityInt < min {
				min = passProbabilityInt - 1
			}
			lineY = append(lineY, passProbability.String())
			histogramY = append(histogramY, productMap[month][0])
		}
		month = carbon.Parse(month).AddMonth().Format("Y-m")
	}
	var binX, binHistogramY, binLineY []string
	for bin := range binMap {
		if bin != "1" {
			binX = append(binX, bin)
		}
	}
	sort.Slice(binX, func(i, j int) bool {
		return binMap[binX[i]] > binMap[binX[j]]
	})
	var accumulation float64
	testDecimal, _ := decimal.NewFromString(testStr)
	passDecimal, _ := decimal.NewFromString(passStr)
	failQuantity, _ := testDecimal.Sub(passDecimal).Float64()
	for _, bin := range binX {
		binHistogramY = append(binHistogramY, decimal.NewFromFloat(binMap[bin]).String())
		accumulation += binMap[bin]
		binLineY = append(binLineY, decimal.NewFromFloat(accumulation).Div(decimal.NewFromFloat(failQuantity)).
			Round(4).Mul(decimal.NewFromFloat(100)).String())
	}
	line = &model.Line{
		Name: r.Product,
		X:    x,
		Y:    lineY,
	}
	histogram = &model.Histogram{
		Field: r.Product,
		X:     x,
		Y:     histogramY,
	}
	binLine = &model.Line{
		Name: r.Product,
		X:    binX,
		Y:    binLineY,
	}
	binHistogram = &model.Histogram{
		Field: r.Product,
		X:     binX,
		Y:     binHistogramY,
	}
	return line, histogram, binLine, binHistogram
}
