package report

import (
	"encoding/json"
	"errors"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/exception"
	"eta/eta_mini_ht_api/common/utils/date"
	"eta/eta_mini_ht_api/common/utils/page"
	permissionService "eta/eta_mini_ht_api/domian/config"
	mediaService "eta/eta_mini_ht_api/domian/media"
	productService "eta/eta_mini_ht_api/domian/merchant"
	reportService "eta/eta_mini_ht_api/domian/report"
	userService "eta/eta_mini_ht_api/domian/user"
	productDao "eta/eta_mini_ht_api/models/merchant"
	"eta/eta_mini_ht_api/service/config"
	user "eta/eta_mini_ht_api/service/user"
	"fmt"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	SourceETA           = "ETA"
	SourceHT            = "HT"
	RiskLevelUnMatch    = "unMatch"
	RiskLevelUnTest     = "unTest"
	RiskLevelExpired    = "expired"
	RiskLevelMatch      = "match"
	defaultProductPrice = "0"
)

type PublishRankedReport struct {
	Id                int            `json:"reportId"`
	OrgId             int            `json:"orgId"`
	Title             string         `json:"title"`
	Abstract          string         `json:"abstract"`
	SecondPermissions map[int]string `json:"-"`
	Permissions       map[int]string `json:"-"`
	PermissionNames   interface{}    `json:"permissionNames,omitempty"`
	PublishedTime     string         `json:"publishedTime"`
	CoverUrl          string         `json:"coverUrl"`
	RiskLevel         string         `json:"riskLevel"`
	IsFree            bool           `json:"isFree"`
	Price             string         `json:"price"`
	IsSubscribe       bool           `json:"isSubscribe"`
	Login             bool           `json:"login"`
}

type HotRankedReport struct {
	Id                int            `json:"reportId"`
	OrgId             int            `json:"orgId"`
	Abstract          string         `json:"abstract"`
	Count             int            `json:"count"`
	Title             string         `json:"title"`
	PublishedTime     string         `json:"publishedTime"`
	SecondPermissions map[int]string `json:"-"`
	Permissions       map[int]string `json:"-"`
	PermissionNames   interface{}    `json:"permissionNames,omitempty"`
	CoverUrl          string         `json:"coverUrl"`
	RiskLevel         string         `json:"riskLevel"`
	IsFree            bool           `json:"isFree"`
	Price             string         `json:"price"`
	IsSubscribe       bool           `json:"isSubscribe"`
	Login             bool           `json:"login"`
}

type RecordCount struct {
	UserId     int
	TraceId    string
	Mobile     string
	ReportId   int
	IpAddress  string
	Location   string
	Referer    string
	Additional string
}

func matchRiskLevel(userId int, report reportService.ReportDTO) (riskLevelMatch string, riskLevel string, err error) {
	userProfile, userErr := user.GetUserProfile(userId)
	if userErr != nil {
		if errors.Is(userErr, gorm.ErrRecordNotFound) {
			logger.Error("用户信息不存在,mobile:%d", userProfile.Mobile)
			err = exception.New(exception.TemplateUserNotFound)
			return
		} else {
			logger.Error("获取用户信息失败:%v", userErr)
			err = exception.New(exception.TemplateUserFoundFailed)
			return
		}
	}
	//比较风险等级
	if userProfile.RiskLevelStatus == user.RiskUnTest {
		logger.Info("客户风险等级未测试,mobile:%d", userProfile.Mobile)
		riskLevelMatch = RiskLevelUnTest
		return
	}
	if userProfile.RiskLevelStatus == user.RiskExpired {
		logger.Info("客户风险等级已过期,mobile:%v", userProfile.Mobile)
		riskLevelMatch = RiskLevelExpired
		return
	}
	level, err := permissionService.GetRiskMappingByCustomerRiskLevel(userProfile.RiskLevel)
	if err != nil {
		logger.Error("获取eta报告风险等级失败:%v", err)
		return
	}
	permissions := reportService.GetReportSecondPermissionsById(report.OrgId, report.Source)
	if len(permissions) == 0 {
		logger.Error("获取eta报告分类失败:%v", err)
		riskLevelMatch = RiskLevelUnMatch
		return
	}
	var permissionIds []int
	for _, permission := range permissions {
		permissionIds = append(permissionIds, permission.PermissionId)
	}
	permissionDTOs, err := permissionService.GetPermissionListByIds(permissionIds)
	if err != nil {
		logger.Error("获取品种风险等级失败:%v", err)
		return
	}
	//能够查看最高等级
	matchNum, err := config.ParseRiskLevel(level.ProductRiskLevel)
	if err != nil {
		logger.Error("解析风险等级失败:%v", err)
		return
	}
	if len(permissionDTOs) == 0 {
		logger.Error("当前报告对应品种未设置风险等级")
		err = exception.New(exception.ReportRiskLevelUnSet)
		return
	}
	//能够查看需要的最小等级
	//num := getLowestRiskLevel(permissionDTOs)
	num := config.GetHighestRiskLevel(permissionDTOs)
	riskLevel = fmt.Sprintf("R%d", num)
	if num > matchNum {
		riskLevelMatch = RiskLevelUnMatch
		return
	} else {
		riskLevelMatch = RiskLevelMatch
		return
	}
}

func GetReportById(reportId int, login bool, userId int) (report reportService.ReportDTO, err error) {
	report, err = reportService.GetReportById(reportId)
	if err != nil {
		logger.Error("获取研报失败:%v", err)
		err = exception.New(exception.GetReportFailed)
		return
	}
	var status string
	status, report.RiskLevel, err = matchRiskLevel(userId, report)
	if err != nil {
		logger.Error("匹配风险等级失败:%v", err)
		err = exception.New(exception.ReportRiskLevelUnSet)
		return
	}
	var pdfUrl string
	switch report.Source {
	case SourceETA:
		var detail reportService.ETAReportDTO
		detail, err = getETAReportDetail(&report)
		if err != nil {
			logger.Error("获取研报详情失败失败:%v", err)
			err = exception.New(exception.GetReportFailed)
			return
		}
		if !login {
			detail.Content = ""
			report.RiskLevelStatus = RiskLevelUnMatch
			report.Login = false
		} else {
			if status != RiskLevelMatch {
				detail.Content = ""
			}
			report.RiskLevelStatus = status
			report.Login = true
		}
		var jsonStr []byte
		jsonStr, err = json.Marshal(detail)
		if err != nil {
			logger.Error("生成研报详情失败:%v", err)
			err = exception.New(exception.GetReportFailed)
		}
		report.Detail = jsonStr
		return
	case SourceHT:
		pdfUrl, err = getHTReportDetail(&report)
		if err != nil {
			logger.Error("获取研报详情失败失败:%v")
			err = exception.New(exception.GetReportFailed)
			return
		}
		if !login {
			report.PdfUrl = ""
			report.RiskLevelStatus = RiskLevelUnMatch
			report.Login = false
		} else {
			if status == RiskLevelMatch {
				report.PdfUrl = pdfUrl
			}
			report.RiskLevelStatus = status
			report.Login = true
		}
		return
	default:
		logger.Error("不支持的研报来演:%v")
		err = exception.New(exception.GetReportFailed)
		return
	}
}

func getETAReportDetail(report *reportService.ReportDTO) (etaReport reportService.ETAReportDTO, err error) {
	return reportService.GetETAReport(report.OrgId)
}

func getHTReportDetail(report *reportService.ReportDTO) (url string, err error) {
	return reportService.GetHtReport(report.OrgId)
}
func GetTotalPageCountByPermissionIds(permissionIds []int, isLogin bool, userId int) (total int64, latestId int64, ids map[string][]int) {
	return getCount(permissionIds, isLogin, userId)
}
func filterPermissionsByRisk(permissionList []permissionService.PermissionDTO, riskLevel string) (resultList []permissionService.PermissionDTO) {
	if riskLevel != "" {
		riskLevelNum, err := config.ParseRiskLevel(riskLevel)
		if err != nil {
			logger.Error("风险等级解析失败:%v", err)
			return
		}
		for _, permission := range permissionList {
			pRiskNum, riskErr := config.ParseRiskLevel(permission.RiskLevel)
			if riskErr != nil {
				logger.Error("解析品种风险等级失败 permission:%d,risk:%v", permission.PermissionId, permission.RiskLevel)
				continue
			}
			if pRiskNum <= riskLevelNum {
				resultList = append(resultList, permission)
			}
		}
	} else {
		resultList = permissionList
	}
	return
}

// ParseRiskLevel 解析风险等级字符串,并返回数字部分

func SearchReportList(key string, Ids []int, pageInfo page.PageInfo, isLogin bool, userId int) (list []reportService.ReportDTO, err error) {
	offset := page.StartIndex(pageInfo.Current, pageInfo.PageSize)
	var reports []reportService.ReportDTO
	reports, err = reportService.SearchReportList(key, Ids, offset, pageInfo.PageSize, pageInfo.LatestId)
	list, err = dealReportInfo(reports, isLogin, userId)
	if err != nil {
		err = exception.New(exception.SearchReportPageFailed)
	}
	return
}
func RangeSearchByAnalyst(analystName string, userId int) (total int64, latestId int64, ids []int) {
	return getCountByAnalyst(nil, true, userId, analystName)
}
func RangeSearch(key string, isLogin bool, userId int) (total int64, latestId int64, reportIds []int, err error) {
	var orgIds map[string][]int
	_, latestId, orgIds = getCount(nil, isLogin, userId)
	reportIds, err = GetReportByIdListByOrgIds(orgIds)
	if err != nil {
		logger.Error("获取报告ID列表失败:%v", err)
		err = exception.NewWithException(exception.GetReportSearchRangeFailed, err.Error())
		return
	}
	total = reportService.SearchMaxReportIdWithRange(key, reportIds)
	return
}
func dealReportInfo(list []reportService.ReportDTO, isLogin bool, userId int) (resultList []reportService.ReportDTO, err error) {
	var wg sync.WaitGroup
	wg.Add(len(list))
	for i := 0; i < len(list); i++ {
		go func(report *reportService.ReportDTO) {
			defer wg.Done()
			report.Login = isLogin
			report.Permissions, report.PermissionNames = GetReportPermissionNames(report.OrgId, report.Source)
			var permissions []permissionService.PermissionDTO
			permissions, report.SecondPermission = getReportSecondPermissions(report.OrgId, report.Source)
			if len(permissions) == 0 {
				return
			}
			riskNum := config.GetHighestRiskLevel(permissions)
			report.RiskLevel = strings.Join([]string{"R", strconv.Itoa(riskNum)}, "")
			var src string
			src, err = mediaService.GetImageSrc(report.CoverSrc)
			if err != nil {
				logger.Error("获取图片地址失败:%v", err)
				src = ""
			} else {
				report.CoverUrl = src
			}
			//查询产品信息
			product, pdErr := productService.GetProductBySourceId(report.ReportID, productDao.Report)
			if pdErr != nil {
				if errors.Is(pdErr, gorm.ErrRecordNotFound) {
					var permissionIds []int
					if len(permissions) > 0 {
						for _, permission := range permissions {
							permissionIds = append(permissionIds, permission.PermissionId)
						}
						//单品不存在的话查套餐
						productList, prodErr := productService.GetProductListBySourceIds(permissionIds, "package")
						if prodErr != nil || len(productList) == 0 {
							logger.Error("获取套餐列表失败:%v", pdErr)
							report.Price = defaultProductPrice
							report.IsFree = true
							report.IsSubscribe = false
							report.IsPackage = false
						} else {
							report.Price = defaultProductPrice
							report.IsFree = true
							report.IsSubscribe = false
							report.IsPackage = true
							report.ProductId = productList[0].Id
						}
					} else {
						report.Price = defaultProductPrice
						report.IsFree = true
						report.IsSubscribe = false
						report.IsPackage = false
					}
				} else {
					report.Price = defaultProductPrice
					report.IsFree = false
					report.IsSubscribe = false
					report.IsPackage = false
				}
			} else {
				report.Price = product.Price.String()
				report.IsFree = false
				report.ProductId = product.Id
				report.IsPackage = false
				if isLogin {
					subscribe, subscribeErr := userService.GetUserSubscribe(product.Id, userId)
					if subscribeErr != nil {
						report.IsSubscribe = false
					} else {
						report.IsSubscribe = subscribe.Status == productDao.SubscribeValid
					}
				}
			}
		}(&list[i])
	}
	wg.Wait()
	resultList = list
	return
}

// GetReportPage 分页获取报告列表
func GetReportPage(pageInfo page.PageInfo, orgIds map[string][]int, searchAll bool, isLogin bool, userId int) (reports []reportService.ReportDTO, err error) {
	var list []reportService.ReportDTO
	list, err = reportService.GetReportPageByOrgIds(pageInfo, orgIds, searchAll)
	reports, err = dealReportInfo(list, isLogin, userId)

	if err != nil {
		err = exception.New(exception.QueryReportPageFailed)
	}
	return
}
func GetReportPageByAnalyst(pageInfo page.PageInfo, analyst string, reportIds []int) (list []reportService.ReportDTO, err error) {
	list, err = reportService.GetReportPageByAnalyst(pageInfo, analyst, reportIds)
	//并发获取研报的标签
	var wg sync.WaitGroup
	wg.Add(len(list))
	for i := 0; i < len(list); i++ {
		go func(report *reportService.ReportDTO) {
			defer wg.Done()
			report.Permissions, report.PermissionNames = GetReportPermissionNames(report.OrgId, report.Source)
		}(&list[i])
	}
	wg.Wait()
	if err != nil {
		err = exception.New(exception.QueryReportPageFailed)
	}
	return
}
func CountReport(count RecordCount) (traceId string, err error) {
	dto := convertToRecordCountDTO(count)
	return userService.CountReport(dto)
}
func GetRandedReportByWeeklyHot(limit int, isLogin bool, userId int, pdRiskLevel string) (reports []HotRankedReport, err error) {
	end := time.Now()
	begin := date.GetBeginOfTheWeek(end, time.Monday)
	hotReports := userService.GetHotReports(begin.Format(time.DateOnly), end.Format(time.DateOnly), limit)
	if len(hotReports) > 0 {
		var dtoList []reportService.ReportDTO
		var ids []int
		for i := 0; i < len(hotReports); i++ {
			ids = append(ids, hotReports[i].ReportId)
		}
		dtoList, err = reportService.GetListByCondition("id", ids)
		if err != nil {
			logger.Error("获取本周最热研报列表失败:%v", err)
			err = exception.New(exception.GetHotRandListFailed)
			return
		}
		dtoList, err = dealReportInfo(dtoList, isLogin, userId)
		if err != nil {
			logger.Error("获取本周最热研报列表失败:%v", err)
			err = exception.New(exception.GetHotRandListFailed)
			return
		}
		var filterList []reportService.ReportDTO
		if pdRiskLevel != "" {
			for _, report := range dtoList {
				pdRiskNum, paresErr := config.ParseRiskLevel(report.RiskLevel)
				if paresErr != nil {
					logger.Error("解析风险等级失败:%v", err)
					continue
				}
				reRiskNum, paresErr := config.ParseRiskLevel(pdRiskLevel)
				if paresErr != nil {
					logger.Error("解析风险等级失败:%v", err)
					continue
				}

				if pdRiskNum <= reRiskNum {
					filterList = append(filterList, report)
				}
			}
		}
		reports = make([]HotRankedReport, len(ids))
		for i := 0; i < len(filterList); i++ {
			report := convertToHotRankedReport(filterList[i])
			for j := 0; j < len(hotReports); j++ {
				if hotReports[j].ReportId == report.Id {
					report.Count = hotReports[j].Count
					reports[j] = report
					break
				}
			}
		}
	} else {
		reports = []HotRankedReport{}
	}
	return
}

func GetRandedReportByPublishTimeWeekly(limit int, week bool, isLogin bool, userId int, pdRiskLevel string) (reports []PublishRankedReport, err error) {
	dtoList, err := reportService.GetListOrderByConditionWeekly(week, "published_time", limit, reportService.DESC)
	if err != nil {
		logger.Error("获取最新发布的研报列表失败:%v", err)
		err = exception.New(exception.GetPublishedRandListFailed)
		return
	}
	var filterList []reportService.ReportDTO
	dtoList, err = dealReportInfo(dtoList, isLogin, userId)
	if err != nil {
		logger.Error("获取最新发布的研报列表失败:%v", err)
		err = exception.New(exception.GetPublishedRandListFailed)
		return
	}
	if pdRiskLevel != "" {
		for _, report := range dtoList {
			pdRiskNum, paresErr := config.ParseRiskLevel(report.RiskLevel)
			if paresErr != nil {
				logger.Error("解析风险等级失败:%v", err)
				continue
			}
			reRiskNum, paresErr := config.ParseRiskLevel(pdRiskLevel)
			if paresErr != nil {
				logger.Error("解析风险等级失败:%v", err)
				continue
			}
			if pdRiskNum <= reRiskNum {
				filterList = append(filterList, report)
			}
		}
	}
	reports = convertToPublishRankedReportList(filterList)
	return
}

func GetReportPermissionNames(id int, source string) (permissionMap map[int]string, labels []string) {
	permissions := reportService.GetReportPermissionsById(id, source)
	permissionMap = make(map[int]string, len(permissions))
	if len(permissions) > 0 {
		for _, permission := range permissions {
			labels = append(labels, permission.PermissionName)
			permissionMap[permission.PermissionId] = permission.PermissionName
		}
	}
	return
}
func GetReportSecondPermissionsMap(id int, source string) (permissionMap map[int]string) {
	permissionMap = make(map[int]string)
	permissions := reportService.GetReportSecondPermissionsById(id, source)
	for _, permission := range permissions {
		permissionMap[permission.PermissionId] = permission.PermissionName
	}
	return
}

func getReportSecondPermissions(id int, source string) (permissionList []permissionService.PermissionDTO, secondPermissionMap map[int]string) {
	permissionList = reportService.GetReportSecondPermissionsById(id, source)
	if len(permissionList) > 0 {
		secondPermissionMap = make(map[int]string, len(permissionList))
		for _, permission := range permissionList {
			secondPermissionMap[permission.PermissionId] = permission.PermissionName
		}
	}
	return
}
func getReportPermissionsMap(id int, source string) (permissionMap map[int]string) {
	permissionMap = make(map[int]string)
	permissions := reportService.GetReportPermissionsById(id, source)
	for _, permission := range permissions {
		permissionMap[permission.PermissionId] = permission.PermissionName
	}
	return
}
func GetPermissionList() (root *permissionService.PermissionNode, err error) {
	return permissionService.GetPermissionList()
}

func convertToHotRankedReport(dto reportService.ReportDTO) (report HotRankedReport) {
	report = HotRankedReport{
		Id:                dto.ReportID,
		OrgId:             dto.OrgId,
		Abstract:          dto.Abstract,
		PublishedTime:     dto.PublishedTime,
		Title:             dto.Title,
		SecondPermissions: dto.SecondPermission,
		Permissions:       dto.Permissions,
		PermissionNames:   dto.PermissionNames,
		CoverUrl:          dto.CoverUrl,
		IsSubscribe:       dto.IsSubscribe,
		IsFree:            dto.IsFree,
		Price:             dto.Price,
		RiskLevel:         dto.RiskLevel,
		Login:             dto.Login,
	}
	return
}
func convertToPublishRankedReportList(dtoList []reportService.ReportDTO) (reports []PublishRankedReport) {
	reports = []PublishRankedReport{}
	for _, dto := range dtoList {
		risk, err := config.ParseRiskLevel(dto.RiskLevel)
		if err != nil || risk == 0 {
			continue
		}
		src, err := mediaService.GetImageSrc(dto.CoverSrc)
		if err != nil {
			logger.Error("获取封面图片失败:%v", err)
			src = ""
		}
		report := PublishRankedReport{
			Id:                dto.ReportID,
			OrgId:             dto.OrgId,
			PublishedTime:     dto.PublishedTime,
			Abstract:          dto.Abstract,
			Title:             dto.Title,
			Permissions:       dto.Permissions,
			SecondPermissions: dto.SecondPermission,
			PermissionNames:   dto.PermissionNames,
			CoverUrl:          src,
			IsSubscribe:       dto.IsSubscribe,
			IsFree:            dto.IsFree,
			Price:             dto.Price,
			RiskLevel:         dto.RiskLevel,
			Login:             dto.Login,
		}
		reports = append(reports, report)
	}
	return
}

func convertToRecordCountDTO(record RecordCount) (dto userService.RecordCountDTO) {
	return userService.RecordCountDTO{
		UserId:     record.UserId,
		TraceId:    record.TraceId,
		Mobile:     record.Mobile,
		SourceId:   record.ReportId,
		IpAddress:  record.IpAddress,
		Location:   record.Location,
		Referer:    record.Referer,
		Additional: record.Additional,
	}
}

func GetReportByIdListByOrgIds(orgIds map[string][]int) (ids []int, err error) {
	ids, err = reportService.GetReportByIdListByOrgIds(orgIds)
	if err != nil {
		logger.Error("获取报告ID列表失败:%v", err)
		err = exception.New(exception.GetReportSearchRangeFailed)
	}
	return
}

func RangePermissionIds(isLogin bool, userId int) (filterPermissionIds []int, riskLevel string, err error) {
	return CheckUserRisk(nil, isLogin, userId)
}
func CheckUserRisk(permissionIds []int, isLogin bool, userId int) (filterPermissionIds []int, riskLevel string, err error) {
	if isLogin {
		userProfile, userErr := user.GetUserProfile(userId)
		if userErr != nil {
			if errors.Is(userErr, gorm.ErrRecordNotFound) {
				err = exception.New(exception.TemplateUserNotFound)
			} else {
				err = exception.New(exception.TemplateUserFoundFailed)
			}
			logger.Error("分页查询报告列表失败:%v", err)
			return
		}
		//获取产品风险等级
		if userProfile.RiskLevelStatus == user.RiskUnTest {
			logger.Warn("客户未做风险等级测评,mobile:%v", userProfile.Mobile)
		}
		if userProfile.RiskLevelStatus == user.RiskExpired {
			logger.Warn("客户风险等级已过期,mobile:%v", userProfile.Mobile)
		}
		var mapping permissionService.CustomerProductRiskMappingDTO
		if userProfile.RiskLevel != "" {
			mapping, err = permissionService.GetRiskMappingByCustomerRiskLevel(userProfile.RiskLevel)
			if err != nil {
				logger.Error("查询产品风险等级映射失败:%v", err)
				return
			}
		}
		var permissionList []permissionService.PermissionDTO
		if len(permissionIds) == 0 {
			//获取所有设置风险等级的品种
			permissionList, err = permissionService.GetPermissionListWithRisk()
		} else {
			//更具id过滤设置了风险等级的品种
			permissionList, err = permissionService.GetPermissionListByIds(permissionIds)
		}
		permissionList = filterPermissionsByRisk(permissionList, mapping.ProductRiskLevel)
		riskLevel = mapping.ProductRiskLevel
		if len(permissionList) == 0 {
			return
		}
		for _, permission := range permissionList {
			filterPermissionIds = append(filterPermissionIds, permission.PermissionId)
		}
		return
	} else { //没有登录的时候展示所有设置了风险等级的品种报告,筛选的时候过滤传入ID中没有设置风险等级的品种
		var permissionList []permissionService.PermissionDTO
		if len(permissionIds) == 0 {
			//获取所有设置风险等级的品种
			permissionList, err = permissionService.GetPermissionListWithRisk()
		} else {
			//更具id过滤设置了风险等级的品种
			permissionList, err = permissionService.GetPermissionListByIds(permissionIds)
		}
		if err != nil {
			logger.Error("根据ID查询品种列表失败:%v", err)
		}
		for _, permission := range permissionList {
			filterPermissionIds = append(filterPermissionIds, permission.PermissionId)
		}
		//查询品种
		return
	}
}
func getCount(permissionIds []int, isLogin bool, userId int) (total int64, latestId int64, ids map[string][]int) {
	filterPermissionIds, riskLevel, err := CheckUserRisk(permissionIds, isLogin, userId)
	if err != nil {
		logger.Error("校验用户风险等级失败:%v", err)
		return
	}
	return reportService.GetTotalPageCountByPermissionIds(filterPermissionIds, riskLevel)
}

func getCountByAnalyst(permissionIds []int, isLogin bool, userId int, analystName string) (total int64, latestId int64, ids []int) {
	filterPermissionIds, riskLevel, err := CheckUserRisk(permissionIds, isLogin, userId)
	if err != nil {
		logger.Error("校验用户风险等级失败:%v", err)
		return
	}
	return reportService.GetTotalPageCountByAnalyst(analystName, filterPermissionIds, riskLevel)
}