package Wx

import (
	"context"
	"fmt"
	reqv3 "github.com/imroc/req/v3"
	"github.com/suyuan32/simple-admin-core/rpc/types/core"
	"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/suyuan32/simple-admin-common/utils/pointy"
	"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 !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

	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]

		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:       &serverInfo.Name,
				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,
			})
	}

	return resp, nil
}