package sop_task

import (
	"context"
	"errors"
	"github.com/suyuan32/simple-admin-common/msg/errormsg"
	"wechat-api/ent"
	"wechat-api/ent/contact"
	"wechat-api/ent/custom_types"
	"wechat-api/ent/labelrelationship"
	"wechat-api/ent/messagerecords"
	"wechat-api/ent/predicate"
	"wechat-api/ent/soptask"
	"wechat-api/internal/utils/dberrorhandler"

	"wechat-api/internal/svc"
	"wechat-api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

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

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

func (l *PublishSopTaskLogic) PublishSopTask(req *types.IDReq) (resp *types.BaseMsgResp, err error) {
	// 开始事务
	//tx, err := l.svcCtx.DB.Tx(context.Background())
	//if err != nil {
	//	return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
	//}

	// 根据 id 查询 sop_task
	sopTask, err := l.svcCtx.DB.SopTask.Query().
		Where(
			soptask.ID(req.Id),
			soptask.Status(1),
		).
		WithTaskStages().
		Only(l.ctx)
	if err != nil {
		//_ = tx.Rollback()
		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
	}

	// 判断 sop_task 是否存在
	if sopTask != nil {
		if sopTask.BotWxidList == nil {
			return nil, errors.New(errormsg.ValidationError)
		}

		// 查询任务的所有 sop_stages
		err = l.svcCtx.DB.SopTask.UpdateOneID(req.Id).
			SetStatus(3).
			Exec(l.ctx)

		if err != nil {
			//_ = tx.Rollback()
			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
		}

		sopStages, err := l.svcCtx.DB.SopStage.Query().All(l.ctx)
		if err != nil {
			//_ = tx.Rollback()
			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
		}

		// 遍历 stage
		for _, stage := range sopTask.Edges.TaskStages {
			if stage.ConditionType == 1 {
				// 构造查询条件
				var predicates []predicate.Contact

				for _, condition := range stage.ConditionList {
					subPredicate := contact.HasContactRelationshipsWith(
						labelrelationship.LabelIDIn(condition.LabelIdList...),
						labelrelationship.DeletedAtIsNil())
					if condition.Equal == 2 {
						subPredicate = contact.Not(subPredicate)
					}
					predicates = append(predicates, subPredicate)
				}

				// 查询满足条件的联系人
				var contacts []*ent.Contact
				var err error
				sourceType := 3
				if stage.ConditionOperator == 1 {
					contacts, err = l.svcCtx.DB.Contact.Query().Where(contact.And(predicates...)).All(l.ctx)
				} else {
					contacts, err = l.svcCtx.DB.Contact.Query().Where(contact.Or(predicates...)).All(l.ctx)
				}

				if err != nil {
					//_ = tx.Rollback()
					return nil, err
				}

				// 遍历 contacts
				for _, c := range contacts {
					// 判断联系人所属微信是否包含在任务当中
					if sopTask.BotWxidList == nil || (sopTask.BotWxidList != nil && valueInArray(c.WxWxid, sopTask.BotWxidList)) {
						for i, message := range stage.ActionMessage {
							meta := custom_types.Meta{}
							if message.Meta != nil {
								meta.Filename = message.Meta.Filename
							}

							_, _ = l.svcCtx.DB.MessageRecords.Create().
								SetNotNilBotWxid(&c.WxWxid).
								SetNotNilContactID(&c.ID).
								SetNotNilContactType(&c.Type).
								SetNotNilContactWxid(&c.Wxid).
								SetNotNilContentType(&message.Type).
								SetNotNilContent(&message.Content).
								SetMeta(meta).
								SetNotNilSourceType(&sourceType).
								SetNotNilSourceID(&stage.ID).
								SetSubSourceID(uint64(i)).
								Save(l.ctx)

							//if err != nil {
							//	return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
							//}
						}

						// 查询当前联系人的标签关系
						currentLabelRelationships, err := l.svcCtx.DB.LabelRelationship.Query().Where(labelrelationship.ContactID(c.ID)).All(l.ctx)
						if err != nil {
							//_ = tx.Rollback()
							return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
						}

						// 提取当前标签ID
						var currentLabelIds []uint64
						for _, relationship := range currentLabelRelationships {
							currentLabelIds = append(currentLabelIds, relationship.LabelID)
						}

						if stage.ActionLabel != nil {
							// 递归调用 AddLabelRelationships
							err = l.AddLabelRelationships(sopStages, *c, currentLabelIds, stage.ActionLabel)
							if err != nil {
								//_ = tx.Rollback()
								return nil, err
							}
						}
					}
				}
			}
		}
		// 所有操作成功,提交事务
		//err = tx.Commit()
		//if err != nil {
		//	return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
		//}
		return &types.BaseMsgResp{Msg: errormsg.Success}, nil
	} else {
		// 所有操作成功,提交事务
		//err = tx.Commit()
		//if err != nil {
		//	return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
		//}
		//// 返回错误信息:任务不存在
		return nil, errors.New(errormsg.TargetNotFound)
	}
}

func (l *PublishSopTaskLogic) AddLabelRelationships(sopStages []*ent.SopStage, contact ent.Contact, currentLabelIds []uint64, addLabelIds []uint64) (err error) {
	//// 开始事务
	//tx, err := l.svcCtx.DB.Tx(context.Background())
	//if err != nil {
	//	return dberrorhandler.DefaultEntError(l.Logger, err, nil)
	//}

	// 获取 addLabelIds 中不在 currentLabelIds 中的标签ID
	var newLabelIds []uint64
	// 创建一个映射,用于快速查找 currentLabelIds 中的元素
	currentLabelIdSet := make(map[uint64]struct{})
	for _, id := range currentLabelIds {
		currentLabelIdSet[id] = struct{}{}
	}

	// 遍历 addLabelIds,找出不在 currentLabelIds 中的元素
	for _, id := range addLabelIds {
		if _, exists := currentLabelIdSet[id]; !exists {
			newLabelIds = append(newLabelIds, id)
		}
	}

	if len(newLabelIds) == 0 {
		return nil
	}

	// 创建需要新增的标签关系
	for _, id := range newLabelIds {
		_, err = l.svcCtx.DB.LabelRelationship.Create().
			SetLabelID(id).
			SetContactID(contact.ID).
			Save(l.ctx)
		if err != nil {
			//_ = tx.Rollback()
			return dberrorhandler.DefaultEntError(l.Logger, err, nil)
		}
	}

	// 合并 currentLabelIds 和 newLabelIds
	currentLabelIds = append(currentLabelIds, newLabelIds...)

	// 遍历 sop_stages,找出满足条件的 stage
	for _, stage := range sopStages {
		if stage.ConditionType == 1 && isLabelIdListMatchFilter(currentLabelIds, stage.ConditionOperator, stage.ConditionList) {
			// 判断是否有 contact_wxid、source_type、source_id、sub_source_id 相同的记录
			_, err := l.svcCtx.DB.MessageRecords.Query().
				Where(
					messagerecords.ContactWxid(contact.Wxid),
					messagerecords.SourceType(3),
					messagerecords.SourceID(stage.ID),
					messagerecords.SubSourceID(0),
				).
				Only(l.ctx)
			if err != nil {
				continue
			}
			// 判断ActionMessage是否为空
			sourceType := 3
			if stage.ActionMessage != nil {
				for i, message := range stage.ActionMessage {
					meta := custom_types.Meta{}
					if message.Meta != nil {
						meta.Filename = message.Meta.Filename
					}
					_, _ = l.svcCtx.DB.MessageRecords.Create().
						SetNotNilBotWxid(&contact.WxWxid).
						SetNotNilContactID(&contact.ID).
						SetNotNilContactType(&contact.Type).
						SetNotNilContactWxid(&contact.Wxid).
						SetNotNilContentType(&message.Type).
						SetNotNilContent(&message.Content).
						SetMeta(meta).
						SetNotNilSourceType(&sourceType).
						SetNotNilSourceID(&stage.ID).
						SetSubSourceID(uint64(i)).
						Save(l.ctx)

					//if err != nil {
					//	return dberrorhandler.DefaultEntError(l.Logger, err, nil)
					//}
				}
			}
			if stage.ActionLabel != nil {
				// 递归调用 AddLabelRelationships
				err = l.AddLabelRelationships(sopStages, contact, currentLabelIds, stage.ActionLabel)
				if err != nil {
					//_ = tx.Rollback()
					return err
				}
			}
		}

	}

	// 所有操作成功,提交事务
	//err = tx.Commit()
	//if err != nil {
	//	return dberrorhandler.DefaultEntError(l.Logger, err, nil)
	//}
	return nil
}

func valueInArray(val string, array []string) bool {
	for _, item := range array {
		if item == val {
			return true
		}
	}
	return false
}

func isLabelIdListMatchFilter(labelIdList []uint64, conditionOperator int, conditionList []custom_types.Condition) bool {
	labelIdSet := make(map[uint64]struct{})
	for _, id := range labelIdList {
		labelIdSet[id] = struct{}{}
	}

	for _, condition := range conditionList {
		match := false
		for _, id := range condition.LabelIdList {
			if _, ok := labelIdSet[id]; ok {
				match = true
				break
			}
		}

		if condition.Equal == 2 {
			match = !match
		}

		if (conditionOperator == 1 && !match) || (conditionOperator == 2 && match) {
			return match
		}
	}

	return conditionOperator == 1
}