package dao

import (
	"errors"
	"fmt"
	"micro-bundle/internal/model"
	"micro-bundle/pb/bundle"
	"micro-bundle/pkg/app"
	"micro-bundle/pkg/utils"
	"strconv"
	"time"

	"dubbo.apache.org/dubbo-go/v3/common/logger"
	"github.com/duke-git/lancet/v2/datetime"

	"gorm.io/gorm"
)

func AddBundleExtendRecord(data model.BundleExtensionRecords) error {
	return app.ModuleClients.BundleDB.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&data).Error; err != nil {
			return err
		}
		if data.AvailableDurationAdditional != 0 && data.TimeUnit != 0 {
			record := model.BundleOrderRecords{}
			if err := tx.Model(&model.BundleOrderRecords{}).Where(&model.BundleOrderRecords{CustomerID: strconv.Itoa(data.UserId)}).Order("created_at desc").First(&record).Error; err != nil {
				return err
			}
			var expireTime time.Time
			if record.ExpirationTime != "" {
				loc, _ := time.LoadLocation("Asia/Shanghai")
				et, _ := time.ParseInLocation(time.DateTime, record.ExpirationTime, loc)
				expireTime = et
			} else {
				expireTime = time.Now()
				logger.Infof("过期时间为空,使用默认过期时间" + expireTime.Format(time.DateTime))
			}

			switch data.TimeUnit {
			case 1:
				expireTime = datetime.AddDay(expireTime, int64(data.AvailableDurationAdditional))
			case 2:
				expireTime = datetime.AddMonth(expireTime, int64(data.AvailableDurationAdditional))
			case 3:
				expireTime = datetime.AddYear(expireTime, int64(data.AvailableDurationAdditional))
			default:
				return errors.New("时间单位有误")
			}
			record.ExpirationTime = expireTime.Format(time.DateTime)
			return tx.Model(&model.BundleOrderRecords{}).Where(&model.BundleOrderRecords{UUID: record.UUID}).Updates(&record).Error
		}
		return nil
	})
}

func GetBundleExtendRecordList(req *bundle.BundleExtendRecordsListRequest) (data []model.BundleExtendRecordItemPo, total int64, err error) {
	session := app.ModuleClients.BundleDB.Table("fiee_bundle.bundle_extension_records AS ber").
		Select(`
			ber.*,
			rn.name as user_name,
			u.tel_num as user_phone_number
	`).Joins("LEFT JOIN `micro-account`.`user` u on u.id = user_id").
		Joins("LEFT JOIN `micro-account`.`real_name` rn on u.real_name_id  = rn.id").
		Order("created_at desc")
	if req.User != "" {
		if utils.IsPhoneNumber(req.User) {
			session = session.Where("u.tel_num = ?", req.User)
		} else {
			session = session.Where("rn.name like ?", "%"+req.User+"%")
		}
	}
	if req.Operator != "" {
		if utils.IsPhoneNumber(req.Operator) {
			session = session.Where("ber.operator_phone_number = ?", req.Operator)
		} else {
			session = session.Where("ber.operator_name like ?", "%"+req.Operator+"%")
		}
	}
	if req.Type != 0 {
		session = session.Where("ber.`type` = ?", req.Type)
	}
	if req.StartTime != 0 {
		session = session.Where("ber.created_at >= ?", time.UnixMilli(int64(req.StartTime)))
	}
	if req.EndTime != 0 {
		session = session.Where("ber.created_at <= ?", time.UnixMilli(int64(req.EndTime)))
	}
	if req.AssociatedOrderNumber != "" {
		session = session.Where("ber.associated_order_number like ?", "%"+req.AssociatedOrderNumber+"%")
	}
	if err = session.Count(&total).Error; err != nil {
		return
	}
	if req.Page != 0 && req.PageSize != 0 {
		session = session.Limit(int(req.PageSize)).Offset(int(req.Page-1) * int(req.PageSize))
	}
	err = session.Find(&data).Error
	return
}

func GetBundleBalanceList(req *bundle.GetBundleBalanceListReq) (data []model.BundleBalancePo, total int64, err error) {
	subQuery := app.ModuleClients.BundleDB.Table("bundle_order_records as bor1").
		Select("bor1.*").
		Joins(`INNER JOIN (
		SELECT customer_id, MAX(created_at) AS max_created_time
		FROM bundle_order_records
		GROUP BY customer_id
	) bor2 ON bor1.customer_id = bor2.customer_id AND bor1.created_at = bor2.max_created_time`)
	session := app.ModuleClients.BundleDB.Table("`micro-account`.`user` AS u").
		Select(`bb.*, bor.expiration_time as expired_time, bor.bundle_name, bor.status,
	        bor.uuid as order_uuid, rn.name as user_name,
	        u.tel_num as user_phone_number, u.id as user_id`).
		Joins("LEFT JOIN `micro-account`.real_name rn ON u.real_name_id = rn.id").
		Joins("LEFT JOIN (?) as bor ON bor.customer_id = u.id", subQuery).
		Joins("LEFT JOIN fiee_bundle.bundle_balance bb ON u.id = bb.user_id AND bb.order_uuid = bor.uuid").
		Where("rn.name IS NOT NULL").
		Where("u.deleted_at = 0")
	if req.UserName != "" {
		if utils.IsPhoneNumber(req.UserName) {
			session = session.Where("u.tel_num = ?", req.UserName)
		} else {
			session = session.Where("rn.name like ?", "%"+req.UserName+"%")
		}
	}
	if req.Status != 0 {
		session = session.Where("bor.status = ?", req.Status)
	}
	if req.BundleName != "" {
		session = session.Where("bor.bundle_name like ?", "%"+req.BundleName+"%")
	}
	if req.ExpiredTimeEnd != 0 {
		session = session.Where("bor.expiration_time <= ?", time.UnixMilli(req.ExpiredTimeEnd))
	}
	if req.ExpiredTimeStart != 0 {
		session = session.Where("bor.expiration_time >= ?", time.UnixMilli(req.ExpiredTimeStart))
	}
	if req.Bought == 2 {
		session = session.Where("bor.uuid IS NOT NULL")
	}
	if req.Bought == 1 {
		session = session.Where("bor.uuid IS NULL")
	}
	err = session.Count(&total).Error
	if err != nil {
		return
	}
	if req.Page != 0 && req.PageSize != 0 {
		session = session.Limit(int(req.PageSize)).Offset(int(req.Page-1) * int(req.PageSize))
	}
	err = session.Find(&data).Error
	return
}

func GetBundleBalanceByUserId(req *bundle.GetBundleBalanceByUserIdReq) (data model.UserBundleBalancePo, err error) {
	err = app.ModuleClients.BundleDB.Table("fiee_bundle.bundle_balance AS bb").
		Select("bb.*,bor.uuid AS order_uuid, bor.bundle_name AS bundle_name, bor.status AS bundle_status, bor.pay_time AS pay_time, bor.expiration_time AS expired_time,bor.amount AS payment_amount,bor.amount_type AS payment_type").
		Joins("LEFT JOIN bundle_order_records bor ON bor.uuid = bb.order_uuid").
		Joins("LEFT JOIN `micro-account`.`user` u ON u.id = bb.user_id").
		Where("bor.deleted_at IS NULL").
		Where("bb.user_id = ?", req.UserId).
		// Where("bor.expiration_time > ?", time.Now()).
		Order("bb.created_at desc").
		First(&data).Error
	if err != nil {
		return
	}
	var additionalInfo model.UserBundleBalancePo
	err = app.ModuleClients.BundleDB.Model(&model.BundleExtensionRecords{}).
		Select("user_id, SUM(account_additional) as account_additional, SUM(images_additional) as image_additional, SUM(video_additional) as video_additional, SUM(data_additional) as data_additional").
		Where("type = 1"). // 手动扩展
		Where("user_id = ?", req.UserId).
		Where("created_at > ?", data.PayTime). // 判断扩展是否生效
		First(&additionalInfo).Error
	if err != nil {
		return
	}
	data.AccountAdditional = additionalInfo.AccountAdditional
	data.VideoAdditional = additionalInfo.VideoAdditional
	data.ImageAdditional = additionalInfo.ImageAdditional
	data.DataAnalysisAdditional = additionalInfo.DataAnalysisAdditional
	return
}

func AddBundleBalanceByUserId(data model.BundleBalance) error {
	return app.ModuleClients.BundleDB.Transaction(func(tx *gorm.DB) error {
		oldData := model.BundleBalance{}
		if err := tx.Model(&model.BundleBalance{}).Where("user_id = ?", data.UserId).Order("created_at desc").First(&oldData).Error; err != nil {
			return errors.New("用户还没有套餐信息")
		}
		newData := model.BundleBalance{
			Model:                         oldData.Model,
			UserId:                        oldData.UserId,
			OrderUUID:                     oldData.OrderUUID,
			AccountNumber:                 oldData.AccountNumber + data.AccountNumber,
			AccountConsumptionNumber:      oldData.AccountConsumptionNumber + data.AccountConsumptionNumber,
			VideoNumber:                   oldData.VideoNumber + data.VideoNumber,
			VideoConsumptionNumber:        oldData.VideoConsumptionNumber + data.VideoConsumptionNumber,
			ImageNumber:                   oldData.ImageNumber + data.ImageNumber,
			ImageConsumptionNumber:        oldData.ImageConsumptionNumber + data.ImageConsumptionNumber,
			DataAnalysisNumber:            oldData.DataAnalysisNumber + data.DataAnalysisNumber,
			DataAnalysisConsumptionNumber: oldData.DataAnalysisConsumptionNumber + data.DataAnalysisConsumptionNumber,
			ExpansionPacksNumber:          oldData.ExpansionPacksNumber + data.ExpansionPacksNumber,
		}

		if newData.AccountConsumptionNumber > newData.AccountNumber ||
			newData.VideoConsumptionNumber > newData.VideoNumber ||
			newData.ImageConsumptionNumber > newData.ImageNumber ||
			newData.DataAnalysisConsumptionNumber > newData.DataAnalysisNumber {
			return errors.New("套餐余量不足")
		}
		return tx.Model(&model.BundleBalance{}).Where("id = ?", oldData.ID).Save(&newData).Error
	})
}

func CreateBundleBalance(data model.BundleBalance) error {
	return app.ModuleClients.BundleDB.Create(&data).Error
}

func GetUsedRecord(req *bundle.GetUsedRecordListReq) (data []model.CostLog, total int64, err error) {
	session := app.ModuleClients.BundleDB.Model(&model.CostLog{})
	if req.Title != "" {
		session = session.Where("title = ?", req.Title)
	}
	if req.Platform != 0 {
		session = session.Where(fmt.Sprintf("JSON_CONTAINS(platform_ids,'%d')", req.Platform))
	}
	if req.Account != "" {
		session = session.Where(fmt.Sprintf(`JSON_CONTAINS(media_names,'"%s"')`, req.Account))
	}
	if req.SubmitTimeEnd != 0 {
		session = session.Where("submit_time <= ?", time.UnixMilli(req.SubmitTimeEnd))
	}
	if req.SubmitTimeStart != 0 {
		session = session.Where("submit_time >= ?", time.UnixMilli(req.SubmitTimeStart))
	}
	if req.User != "" {
		if utils.IsPhoneNumber(req.User) {
			session = session.Where("artist_phone = ?", req.User)
		} else {
			session = session.Where("artist_name like ?", "%"+req.User+"%")
		}
	}
	if req.Operator != "" {
		if utils.IsPhoneNumber(req.Operator) {
			session = session.Where("operator_phone = ?", req.Operator)
		} else {
			session = session.Where("operator_name like ?", "%"+req.Operator+"%")
		}
	}
	if req.Type != 0 {
		session = session.Where("work_category = ?", req.Type)
	}
	if err = session.Count(&total).Error; err != nil {
		return
	}
	if req.Page != 0 && req.PageSize != 0 {
		session = session.Offset(int(req.Page-1) * int(req.PageSize)).Limit(int(req.PageSize))
	}
	err = session.Order("updated_at desc").Find(&data).Error
	return
}

func GetImageWorkDetail(req *bundle.GetImageWorkDetailReq) (data model.CastWorkImage, err error) {
	err = app.ModuleClients.BundleDB.Where(&model.CastWorkImage{WorkUuid: req.WorkId}).First(&data).Error
	return
}

func GetVedioWorkDetail(req *bundle.GetVedioWorkDetailReq) (data model.CastWorkVideo, err error) {
	err = app.ModuleClients.BundleDB.Where(&model.CastWorkVideo{WorkUuid: req.WorkId}).First(&data).Error
	return
}

func ToBeComfirmedWorks(req *bundle.ToBeComfirmedWorksReq) (data []model.CastWorkLog, total int64, unconfirmed int64, err error) {
	subQuery := app.ModuleClients.BundleDB.
		Table("cast_work_log").
		Select("work_uuid, MAX(update_time) AS max_update_time").
		Group("work_uuid").Where("work_status in ?", []int{4, 5, 6, 7})

	err = app.ModuleClients.BundleDB.
		Table("cast_work_log AS cwl").
		Joins("INNER JOIN (?) AS t ON cwl.work_uuid = t.work_uuid AND cwl.update_time = t.max_update_time", subQuery).
		Where("artist_uuid = ?", req.ArtistUuid).Where("confirmed_at = ?", 0).Count(&unconfirmed).Error
	if err != nil {
		return
	}
	session := app.ModuleClients.BundleDB.
		Table("cast_work_log AS cwl").
		Joins("INNER JOIN (?) AS t ON cwl.work_uuid = t.work_uuid AND cwl.update_time = t.max_update_time", subQuery).
		Where("artist_uuid = ?", req.ArtistUuid)
	err = session.Count(&total).Error
	if err != nil {
		return
	}
	if req.Page != 0 && req.PageSize != 0 {
		session.Limit(int(req.PageSize)).Offset(int(req.Page-1) * int(req.PageSize))
	}
	err = session.Order("created_at desc").Find(&data).Error
	return
}

func ConfirmWork(req *bundle.ConfirmWorkReq) error {
	return app.ModuleClients.BundleDB.Model(&model.CastWorkLog{}).Where(&model.CastWorkLog{WorkUuid: req.WorkUuid}).Update("confirmed_at", time.Now().Unix()).Error
}