package product

import (
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/exception"
	"eta/eta_mini_ht_api/common/utils/page"
	permissionService "eta/eta_mini_ht_api/domian/config"
	mediaDomain "eta/eta_mini_ht_api/domian/media"
	merchantService "eta/eta_mini_ht_api/domian/merchant"
	orderDomain "eta/eta_mini_ht_api/domian/order"
	reportDomain "eta/eta_mini_ht_api/domian/report"
	"eta/eta_mini_ht_api/domian/user"
	"eta/eta_mini_ht_api/models/config"
	"eta/eta_mini_ht_api/models/image"
	"eta/eta_mini_ht_api/models/media"
	merchantDao "eta/eta_mini_ht_api/models/merchant"
	configService "eta/eta_mini_ht_api/service/config"
	mediaService "eta/eta_mini_ht_api/service/media"
	"eta/eta_mini_ht_api/service/order"
	reportService "eta/eta_mini_ht_api/service/report"
	"fmt"
	"sort"
	"sync"
	"sync/atomic"
	"time"
)

type ProductDTO struct {
	Id              int      `json:"id"`
	Title           string   `json:"title"`
	SourceTile      string   `json:"sourceTile"`
	Abstract        string   `json:"abstract"`
	Src             string   `json:"src"`
	PermissionNames []string `json:"permissionNames"`
	PermissionIds   []int    `json:"-"`
	Description     string   `json:"description"`
	Price           string   `json:"price"`
	CoverSrc        int      `json:"coverSrc"`
	CoverUrl        string   `json:"coverUrl"`
	RiskLevel       string   `json:"riskLevel"`
	Type            string   `json:"type"`
	BeginDate       string   `json:"beginDate"`
	EndDate         string   `json:"endDate"`
	SourceId        int      `json:"sourceId"`
	IsSubscribe     bool     `json:"isSubscribe"`
	ReportId        int      `json:"reportId"`
	MediaId         int      `json:"mediaId"`
}

func GetProductRiskLevel(product merchantService.MerchantProductDTO) (riskLevel, sourceTitle, sourceAbsract, coverSrc, sourceSrc string, permissionNames []string, permissionIds []int, err error) {
	switch product.Type {
	case "package":
		permissionRisk, permissionErr := config.PermissionsByPermissionId(product.SourceId)
		permissionNames = []string{permissionRisk.Name}
		permissionIds = []int{product.SourceId}
		if permissionErr != nil {
			logger.Error("获取权限信息失败[permissionId:%d]", product.SourceId)
		} else {
			riskLevel = permissionRisk.RiskLevel
		}
		coverSrc = product.CoverUrl
	case "audio", "video":
		mediaInfo, mediaErr := media.GetMediaById(product.Type, product.SourceId)
		sourceTitle, coverSrc, sourceSrc = mediaInfo.MediaName, mediaInfo.CoverSrc, mediaInfo.Src
		if mediaErr != nil {
			logger.Error("获取媒体信息失败[mediaType:%s,mediaId:%d]", product.Type, product.SourceId)
		}
		permissionIds, mediaErr = media.GetMediaPermissionMappingByMedia(product.Type, product.SourceId)
		if mediaErr != nil {
			logger.Error("获取媒体权限失败[mediaType:%s,mediaId:%d]", product.Type, product.SourceId)
		} else {
			permissions, permissionErr := permissionService.GetPermissionListByIds(permissionIds)
			if permissionErr != nil {
				logger.Error("获取权限信息失败[permissionIds:%v]", permissionIds)
			}
			permissionNames = mediaService.GetMediaPermissionNames(permissionIds)
			riskNum := configService.GetHighestRiskLevel(permissions)
			riskLevel = fmt.Sprintf("R%d", riskNum)
		}
	case "report":
		report, reportErr := reportDomain.GetReportById(product.SourceId)
		var coverSrcId int
		sourceAbsract, sourceTitle, coverSrcId = report.Abstract, report.Title, report.CoverSrc
		if coverSrcId > 0 {
			var imageSrc string
			imageSrc, coverSrcErr := image.GetImageSrc(coverSrcId)
			if coverSrcErr != nil {
				logger.Error("获取图片资源失败:%v,资源ID:%d", err, coverSrcId)
			} else {
				coverSrc = imageSrc
			}
		}
		if reportErr != nil {
			logger.Error("获取研报信息失败[reportId:%d]", product.SourceId)
		} else {
			switch report.Source {
			case reportDomain.SourceHT:
				permission, permissionErr := configService.GetPermissionByName(report.PlateName)
				if permissionErr != nil {
					logger.Error("获取板块权限失败[plateName:%s]", report.PlateName)
				} else {
					riskLevel = permission.RiskLevel
					permissionIds = []int{permission.PermissionId}
				}
			case reportDomain.SourceETA:
				permissions, permissionErr := configService.GetSecondPermissionsByClassifyId(report.ClassifyId)
				if permissionErr != nil {
					logger.Error("获取板块权限失败[plateName:%s]", report.PlateName)
				} else {
					riskNum := configService.GetHighestRiskLevel(permissions)
					for _, permission := range permissions {
						permissionIds = append(permissionIds, permission.PermissionId)
					}
					riskLevel = fmt.Sprintf("R%d", riskNum)
				}
			}
			_, permissionNames = reportService.GetReportPermissionNames(report.OrgId, report.Source)
		}
	default:
		logger.Warn("不支持的产品类型[%s]", product.Type)
	}
	return
}
func GetProductInfoById(productId int) (product ProductDTO, err error) {
	merchantProduct, err := merchantService.GetMerchantProductById(productId)
	if err != nil {
		err = exception.NewWithException(exception.ProductInfoError, err.Error())
		return
	}
	product = convertToProductDTO(merchantProduct)
	product.RiskLevel, product.SourceTile, product.Abstract, product.CoverUrl, product.Src, product.PermissionNames, _, err = GetProductRiskLevel(merchantProduct)
	if err != nil {
		logger.Error("获取风险等级失败[productId:%d]", productId)
	}
	return
}
func convertToProductDTO(product merchantService.MerchantProductDTO) (productDTO ProductDTO) {
	beginDate := time.Now()
	endDate := beginDate.Add(time.Duration(product.ValidDays) * 24 * time.Hour)
	productDTO = ProductDTO{
		Id:          product.Id,
		Title:       product.Title,
		Description: product.Description,
		Price:       product.Price,
		RiskLevel:   product.RiskLevel,
		CoverSrc:    product.CoverSrc,
		CoverUrl:    product.CoverUrl,
		Type:        product.Type,
		BeginDate:   beginDate.Format(time.DateOnly),
		EndDate:     endDate.Format(time.DateOnly),
		SourceId:    product.SourceId,
	}
	if product.CoverUrl == "" && product.CoverSrc > 0 {
		imageSrc, err := image.GetImageSrc(product.CoverSrc)
		if err != nil {
			logger.Error("获取图片地址失败:%v,资源Id:%d", err, product.CoverSrc)
		} else {
			productDTO.CoverUrl = imageSrc
		}
	}
	return
}

// OpenProduct 开通产品
func OpenProduct(productOrder orderDomain.ProductOrderDTO) (err error) {
	product, err := merchantService.GetMerchantProductById(productOrder.ProductID)
	if err != nil {
		logger.Error("获取产品信息失败:%v", err)
		return
	}
	return merchantService.OpenProduct(productOrder.TemplateUserID, productOrder.OrderID, product)
}

// CloseProduct  退款关闭套餐
func CloseProduct(templateUserId int, productOrderNo string) (err error) {
	productOrder, err := order.GetProductOrderByUser(templateUserId, productOrderNo)
	if err != nil {
		logger.Error("获取产品订单信息失败:%v", err)
		return
	}
	product, err := merchantService.GetMerchantProductById(productOrder.ProductID)
	if err != nil {
		logger.Error("获取产品信息失败:%v", err)
		return
	}
	return merchantService.CloseProduct(templateUserId, productOrderNo, product)
}

// 过期产品
func ExpireProduct() (err error) {
	_ = user.GetNeedExpiredAccessCount()
	//if err != nil {
	//	logger.Error("获取产品订单信息失败:%v", err)
	//	return
	//}
	//product, err := merchantService.GetMerchantProductById(productOrder.ProductID)
	//if err != nil {
	//	logger.Error("获取产品信息失败:%v", err)
	//	return
	//}
	//return merchantService.CloseProduct(productOrderNo, product)
	return
}
func GetRelatePackage(info ProductDTO) (prodList []ProductDTO, err error) {
	switch info.Type {
	case "audio", "video":
		permissionIds, permissionErr := media.GetMediaPermissionMappingByMedia(info.Type, info.SourceId)
		if permissionErr != nil {
			logger.Error("获取媒体品种信息失败:%v", err)
			return
		}
		merchantProduct, pdErr := merchantService.GetProductListBySourceIds(permissionIds, "package")
		if pdErr != nil {
			return
		}
		for _, product := range merchantProduct {
			prodList = append(prodList, convertToProductDTO(product))
		}
		return
	case "report":
		reportInfo, reportErr := reportDomain.GetReportById(info.SourceId)
		if reportErr != nil {
			logger.Error("获取报告信息失败:%v", err)
			return
		}
		permissions := reportDomain.GetReportSecondPermissionsById(reportInfo.OrgId, reportInfo.Source)
		var permissionIds []int
		if len(permissions) > 0 {
			for _, permission := range permissions {
				permissionIds = append(permissionIds, permission.PermissionId)
			}
			permissionIds = append(permissionIds, permissions[0].PermissionId)
		}
		merchantProduct, pdErr := merchantService.GetProductListBySourceIds(permissionIds, "package")
		if pdErr != nil {
			return
		}
		for _, product := range merchantProduct {
			prodList = append(prodList, convertToProductDTO(product))
		}
		return
	default:
		err = exception.New(exception.ProductTypeError)
		return
	}
}

func GetProductListByProductType(productType string, permissionIds []int, templateUserId int) (total, latestId int64, productIds []int) {
	filterPermissionIds, riskLevel, err := reportService.CheckUserRisk(permissionIds, true, templateUserId)
	if err != nil {
		return
	}
	var dtoList []*ProductDTO
	productList, err := merchantService.GetProductListByProductType(productType)
	var wg sync.WaitGroup
	wg.Add(len(productList))
	for i := 0; i < len(productList); i++ {
		go func(merchantProduct merchantService.MerchantProductDTO) {
			defer wg.Done()
			product := convertToProductDTO(merchantProduct)
			product.RiskLevel, product.SourceTile, product.Abstract, product.CoverUrl, product.Src, product.PermissionNames, product.PermissionIds, err = GetProductRiskLevel(merchantProduct)
			if !compare(product.RiskLevel, riskLevel) {
				return
			}
			match := false
			for _, pdPermissionId := range product.PermissionIds {
				for _, permissionId := range filterPermissionIds {
					if pdPermissionId == permissionId {
						match = true
						break
					}
				}
			}
			if !match {
				return
			}
			dtoList = append(dtoList, &product)
		}(productList[i])
	}
	wg.Wait()
	total = int64(len(dtoList))
	var maxId int
	for i := 0; i < len(dtoList); i++ {
		productIds = append(productIds, dtoList[i].Id)
		if dtoList[i].Id > maxId {
			maxId = dtoList[i].Id
		}
	}
	latestId = int64(maxId)
	return
}

func compare(riskLevel, MatchRiskLevel string) bool {
	pRiskNum, riskErr := configService.ParseRiskLevel(riskLevel)
	if riskErr != nil {
		return false
	}
	riskLevelNum, riskErr := configService.ParseRiskLevel(MatchRiskLevel)
	if riskErr != nil {
		return false
	}
	if pRiskNum <= riskLevelNum {
		return true
	}
	return false
}
func ProductList(productIds []int, templateUserId int, info page.PageInfo) (dtoList []ProductDTO, err error) {
	var merchantProductList []merchantService.MerchantProductDTO
	merchantProductList, err = merchantService.GetProductPageByProductType(productIds, info)
	for _, product := range merchantProductList {
		productDTO := convertToProductDTO(product)
		productDTO.RiskLevel, productDTO.SourceTile, productDTO.Abstract, productDTO.CoverUrl, productDTO.Src, productDTO.PermissionNames, _, err = GetProductRiskLevel(product)
		dtoList = append(dtoList, productDTO)
	}
	var wg sync.WaitGroup
	wg.Add(len(dtoList))
	for i := 0; i < len(dtoList); i++ {
		go func(productDTO *ProductDTO) {
			defer wg.Done()
			productDTO.IsSubscribe = isSubscribeSignal(productDTO.Id, templateUserId)
		}(&dtoList[i])
	}
	return
}
func RangeProductList() (productIdMap map[string][]int, err error) {
	return merchantService.GetProductByProductType()
}
func ProductSearch(key string, templateUserId int, pageInfo page.PageInfo) (list []ProductDTO, err error) {
	var merchantProductList []merchantService.MerchantProductDTO
	var sourceIds []int
	var maxId int
	for _, product := range merchantProductList {
		if product.SourceId > maxId {
			maxId = product.SourceId
		}
		sourceIds = append(sourceIds, product.SourceId)
	}
	//reportList, err := reportDomain.SearchReportList(key, sourceIds, 1, len(sourceIds), int64(maxId))
	//mediaList, err := mediaDomain.SearchMediaList(key)

	for _, product := range merchantProductList {
		productDTO := convertToProductDTO(product)
		list = append(list, productDTO)
	}
	return
}

func convertReportToSearchDTO(report reportDomain.ReportDTO) (dto reportDomain.ProductSearchDTO) {
	return reportDomain.ProductSearchDTO{
		HighLight:  report.Highlight[0],
		SourceId:   report.ReportID,
		SourceType: "report",
		Score:      report.Score,
	}
}
func convertMediaToSearchDTO(media mediaDomain.MediaDTO) (dto reportDomain.ProductSearchDTO) {
	return reportDomain.ProductSearchDTO{
		HighLight:  media.Highlight[0],
		SourceId:   media.MediaId,
		SourceType: media.MediaType,
		Score:      media.Score,
	}
}
func SearchRelateProduct(key string, productIdMap map[string][]int) (list []reportDomain.ProductSearchDTO, err error) {
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		docIds := productIdMap["report"]
		reports, reportErr := reportService.SearchReportProduct(key, docIds)
		if reportErr != nil {
			logger.Error("搜索相关报告失败:%v,key:%s", reportErr, key)
			return
		}
		for _, report := range reports {
			list = append(list, convertReportToSearchDTO(report))
		}
	}()
	go func() {
		defer wg.Done()
		docIds := append(productIdMap["audio"], productIdMap["video"]...)
		medias, mediaErr := mediaService.SearchMediaProduct(key, docIds)
		if mediaErr != nil {
			logger.Error("搜索相关媒体失败:%v,key:%s", mediaErr, key)
			return
		}
		for _, mediaInfo := range medias {
			list = append(list, convertMediaToSearchDTO(mediaInfo))
		}
	}()
	wg.Wait()
	sort.Slice(list, func(i, j int) bool {
		return list[i].Score > list[j].Score
	})
	return
}

func LatestId() (latestId int64) {
	return merchantService.LatestId()
}

func CountSearchPackageList(list []reportDomain.ProductSearchDTO) (total, latestId int64, permissionTotalMap map[int]*atomic.Int32) {
	productIdMap := make(map[string][]int, len(list))
	permissionTotalMap = make(map[int]*atomic.Int32)
	for _, product := range list {
		ids := productIdMap[product.SourceType]
		ids = append(ids, product.SourceId)
		productIdMap[product.SourceType] = ids
	}
	var wg sync.WaitGroup
	wg.Add(len(productIdMap))
	for key, ids := range productIdMap {
		go func(k string, ids []int) {
			defer wg.Done()
			var permissionMap map[int]int
			switch k {
			case "report":
				permissionMap = reportService.CountPermissionWeight(ids)
			case "audio", "video":
				permissionMap = mediaService.CountPermissionWeight(ids)
			}
			for permissionId, weight := range permissionMap {
				if permissionTotalMap[permissionId] == nil {
					permissionTotalMap[permissionId] = new(atomic.Int32)
				}
				permissionTotalMap[permissionId].Add(int32(weight))
			}
		}(key, ids)
	}
	wg.Wait()
	total = int64(len(permissionTotalMap))
	latestId = merchantService.LatestId()
	return
}

func ProductListBySort(isSignal bool, list []reportDomain.ProductSearchDTO, weightMap map[int]*atomic.Int32, templateUserId int, info page.PageInfo) (resultList []ProductDTO, err error) {
	var pdDTOS []merchantService.MerchantProductDTO
	pdDTOS, err = merchantService.ProductListBySort(isSignal, list, weightMap, info)
	var wg sync.WaitGroup
	wg.Add(len(pdDTOS))
	for _, pd := range pdDTOS {
		go func(pd merchantService.MerchantProductDTO) {
			defer wg.Done()
			productDTO := convertToProductDTO(pd)
			productDTO.RiskLevel, productDTO.SourceTile, productDTO.Abstract, productDTO.CoverUrl, productDTO.Src, productDTO.PermissionNames, _, err = GetProductRiskLevel(pd)
			productDTO.IsSubscribe = isSubscribeSignal(pd.Id, templateUserId)
			resultList = append(resultList, productDTO)
		}(pd)
	}
	wg.Wait()
	return
}

func isSubscribeSignal(productId int, templateUserId int) (isSubscribe bool) {
	subscribeList, subErr := user.GetUserSubscribe([]int{productId}, templateUserId)
	if subErr != nil {
		logger.Error("获取用户订阅状态失败:%v", subErr)
		return false
	} else {
		if len(subscribeList) == 0 {
			logger.Error("用户未订阅单品,productId:%v", productId)
			return false
		} else {
			return subscribeList[0].Status == merchantDao.SubscribeValid
		}
	}
}