package Wx

import (
	"context"
	"fmt"
	reqv3 "github.com/imroc/req/v3"
	"github.com/suyuan32/simple-admin-common/utils/pointy"
	"github.com/suyuan32/simple-admin-core/rpc/types/core"
	"strings"
	"wechat-api/ent"
	"wechat-api/ent/predicate"
	"wechat-api/ent/usagetotal"
	"wechat-api/ent/wx"
	"wechat-api/hook"
	"wechat-api/internal/svc"
	"wechat-api/internal/types"
	"wechat-api/internal/utils/dberrorhandler"

	"github.com/suyuan32/simple-admin-common/msg/errormsg"

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

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

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

func (l *GetWxListLogic) GetWxList(req *types.WxListReq) (*types.WxListResp, error) {
	organizationId := l.ctx.Value("organizationId").(uint64)
	isAdmin := l.ctx.Value("isAdmin").(bool)
	servers, err := l.svcCtx.DB.Server.Query().All(l.ctx)
	serverSet := make(map[uint64]*ent.Server, len(servers))
	serverSet[0] = &ent.Server{
		ID:     0,
		Name:   "工作手机",
		Status: 1,
	}
	for _, s := range servers {
		serverSet[s.ID] = s
	}

	var predicates []predicate.Wx
	if req.Ctype != nil && *req.Ctype > 0 {
		predicates = append(predicates, wx.Ctype(*req.Ctype))
	}

	if !isAdmin {
		predicates = append(predicates, wx.OrganizationIDEQ(organizationId))
	} else {
		if req.OrganizationId != nil {
			predicates = append(predicates, wx.OrganizationIDEQ(*req.OrganizationId))
		}
		if req.OrganizationName != nil {
			departmentList, _ := l.svcCtx.CoreRpc.GetDepartmentList(l.ctx, &core.DepartmentListReq{Name: req.OrganizationName})
			organizationIds := make([]uint64, 0)
			for _, department := range departmentList.Data {
				organizationIds = append(organizationIds, *department.Id)
			}
			predicates = append(predicates, wx.OrganizationIDIn(organizationIds...))
		}
	}
	if req.ServerId != nil {
		predicates = append(predicates, wx.ServerIDEQ(*req.ServerId))
	}
	if req.Port != nil {
		predicates = append(predicates, wx.PortContains(*req.Port))
	}
	if req.ProcessId != nil {
		predicates = append(predicates, wx.ProcessIDContains(*req.ProcessId))
	}
	if req.Callback != nil {
		predicates = append(predicates, wx.CallbackContains(*req.Callback))
	}
	data, err := l.svcCtx.DB.Wx.Query().Where(predicates...).Order(ent.Desc(wx.FieldOrganizationID)).WithAgent().WithServer().Page(l.ctx, req.Page, req.PageSize)

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

	resp := &types.WxListResp{}
	resp.Msg = errormsg.Success
	resp.Data.Total = data.PageDetails.Total

	if req.Ctype != nil && *req.Ctype == 3 {
		for _, v := range data.List {
			// 创建 hookClient 客户端
			serverInfo := serverSet[v.ServerID]
			serverName := serverInfo.Name
			processID := v.ProcessID
			wxid := v.Wxid
			account := v.Account
			nickname := v.Nickname
			tel := v.Tel
			headBig := v.HeadBig

			departmentInfo, err := l.svcCtx.CoreRpc.GetDepartmentById(l.ctx, &core.IDReq{Id: v.OrganizationID})
			if err != nil {
				l.Error("获取部门信息失败", err)
			}

			totalTokens := uint64(0)
			usageTotalInfo, _ := l.svcCtx.DB.UsageTotal.Query().
				Where(
					usagetotal.BotID(wxid),
				).
				Only(l.ctx)
			if usageTotalInfo != nil {
				totalTokens = usageTotalInfo.TotalTokens
			}

			var agent types.AgentInfo
			if v.Edges.Agent != nil {
				agent = types.AgentInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id:        &v.AgentID,
						CreatedAt: pointy.GetPointer(v.Edges.Agent.CreatedAt.UnixMilli()),
						UpdatedAt: pointy.GetPointer(v.Edges.Agent.UpdatedAt.UnixMilli()),
					},
					Name:       &v.Edges.Agent.Name,
					Role:       &v.Edges.Agent.Role,
					Status:     &v.Edges.Agent.Status,
					Background: &v.Edges.Agent.Background,
					Examples:   &v.Edges.Agent.Examples,
				}
			}

			resp.Data.Data = append(resp.Data.Data,
				types.WxInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id:        &v.ID,
						CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
						UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
					},
					Status:           &v.Status,
					ServerId:         &v.ServerID,
					ServerName:       &serverName,
					Port:             &v.Port,
					ProcessId:        &processID,
					Callback:         &v.Callback,
					Wxid:             &wxid,
					Account:          &account,
					Nickname:         &nickname,
					Tel:              &tel,
					HeadBig:          &headBig,
					OrganizationId:   &v.OrganizationID,
					OrganizationName: departmentInfo.Name,
					AgentId:          &v.AgentID,
					AgentInfo:        &agent,
					ApiBase:          &v.APIBase,
					ApiKey:           &v.APIKey,
					TotalTokens:      &totalTokens,
					Ctype:            &v.Ctype,
				})
		}
	} else {
		var result types.WorkPhoneGetWeChatsResp

		res, err := reqv3.C().DevMode().R().SetSuccessResult(&result).Post("http://chat.gkscrm.com:13086/pc/GetWeChatsReq?id=13")
		if err != nil {
			return nil, err
		}
		if !res.IsSuccessState() {
			err = fmt.Errorf("GetWeChats failed with status code %d", res.StatusCode)
			return nil, err
		}

		workphoneWxList := make(map[string]types.WorkPhoneWeChat, len(result.Data))
		for _, v := range result.Data {
			workphoneWxList[v.Wechatid] = v
		}

		for _, v := range data.List {
			// 创建 hookClient 客户端
			serverInfo := serverSet[v.ServerID]
			serverName := serverInfo.Name
			if strings.HasPrefix(strings.ToUpper(v.Port), "PC-") {
				serverName = "本地版"
			}
			var loginStatus uint8 = 0
			hookClient := hook.NewHook(serverInfo.PrivateIP, serverInfo.AdminPort, v.Port)
			if v.ServerID > 0 {
				if serverInfo.Status == 1 {
					// 获取登录状态
					loginInfo, err := hookClient.IsLoginStatus()

					if err != nil {
						l.Error("退出登录失败", err)
					} else {
						if loginInfo.Onlinestatus == "3" {
							loginStatus = 1
						}
					}
				}
			} else {
				workphoneWx, exists := workphoneWxList[v.Wxid]
				if exists && workphoneWx.Isonline == 0 {
					loginStatus = 1
				} else {
					loginStatus = 0
				}
			}

			processID := v.ProcessID
			wxid := v.Wxid
			account := v.Account
			nickname := v.Nickname
			tel := v.Tel
			headBig := v.HeadBig

			departmentInfo, err := l.svcCtx.CoreRpc.GetDepartmentById(l.ctx, &core.IDReq{Id: v.OrganizationID})
			if err != nil {
				l.Error("获取部门信息失败", err)
			}

			if v.ServerID > 0 {
				if loginStatus == 1 {
					// 如果处于登录状态，获取登录信息
					wxInfo, _ := hookClient.GetSelfLoginInfo()
					if err != nil {
						l.Error("获取登录信息失败", err)
					} else {
						if wxid != wxInfo.Wxid {
							l.svcCtx.Rds.HDel(l.ctx, "wx_info", wxid)
							l.svcCtx.Rds.HDel(l.ctx, "wx_info", wxInfo.Wxid)
							l.svcCtx.Rds.HDel(l.ctx, "crontask_wx_server_info", wxid)
							l.svcCtx.Rds.HDel(l.ctx, "crontask_wx_server_info", wxInfo.Wxid)
						}
						processID = wxInfo.ProcessID
						wxid = wxInfo.Wxid
						account = wxInfo.Account
						nickname = wxInfo.Nickname
						tel = wxInfo.Tel
						headBig = wxInfo.HeadBig
						_ = l.svcCtx.DB.Wx.UpdateOneID(v.ID).
							SetNotNilStatus(&loginStatus).
							SetNotNilProcessID(&wxInfo.ProcessID).
							SetNotNilWxid(&wxInfo.Wxid).
							SetNotNilAccount(&wxInfo.Account).
							SetNotNilNickname(&wxInfo.Nickname).
							SetNotNilTel(&wxInfo.Tel).
							SetNotNilHeadBig(&wxInfo.HeadBig).
							Exec(l.ctx)
					}
				} else {
					if loginStatus != v.Status {
						_ = l.svcCtx.DB.Wx.UpdateOneID(v.ID).
							SetNotNilStatus(&loginStatus).
							Exec(l.ctx)
					}
				}
			}

			totalTokens := uint64(0)
			usageTotalInfo, _ := l.svcCtx.DB.UsageTotal.Query().
				Where(
					usagetotal.BotID(wxid),
				).
				Only(l.ctx)
			if usageTotalInfo != nil {
				totalTokens = usageTotalInfo.TotalTokens
			}

			var agent types.AgentInfo
			if v.Edges.Agent != nil {
				agent = types.AgentInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id:        &v.AgentID,
						CreatedAt: pointy.GetPointer(v.Edges.Agent.CreatedAt.UnixMilli()),
						UpdatedAt: pointy.GetPointer(v.Edges.Agent.UpdatedAt.UnixMilli()),
					},
					Name:       &v.Edges.Agent.Name,
					Role:       &v.Edges.Agent.Role,
					Status:     &v.Edges.Agent.Status,
					Background: &v.Edges.Agent.Background,
					Examples:   &v.Edges.Agent.Examples,
				}
			}

			resp.Data.Data = append(resp.Data.Data,
				types.WxInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id:        &v.ID,
						CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
						UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
					},
					Status:           &loginStatus,
					ServerId:         &v.ServerID,
					ServerName:       &serverName,
					Port:             &v.Port,
					ProcessId:        &processID,
					Callback:         &v.Callback,
					Wxid:             &wxid,
					Account:          &account,
					Nickname:         &nickname,
					Tel:              &tel,
					HeadBig:          &headBig,
					OrganizationId:   &v.OrganizationID,
					OrganizationName: departmentInfo.Name,
					AgentId:          &v.AgentID,
					AgentInfo:        &agent,
					ApiBase:          &v.APIBase,
					ApiKey:           &v.APIKey,
					TotalTokens:      &totalTokens,
					Ctype:            &v.Ctype,
				})
		}
	}

	return resp, nil
}
