package district

import (
	"context"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/ent"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/ent/district"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/internal/utils/hander"

	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/internal/svc"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/types/core"
)

type GetDistrictTreeLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetDistrictTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetDistrictTreeLogic {
	return &GetDistrictTreeLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetDistrictTreeLogic) GetDistrictTree(in *core.DistrictCodeReq) (*core.DistrictTree, error) {
	var (
		err error
		all []*ent.District
	)
	if in.Code == "" {
		all, err = l.svcCtx.DB.District.Query().
			All(l.ctx)
	} else {
		dbData, err := l.svcCtx.DB.District.Query().
			Where(district.CodeEQ(in.Code)).
			First(l.ctx)
		if err != nil {
			return nil, hander.HandleEntErr(err, in)
		}
		all, err = l.svcCtx.DB.District.Query().
			Where(relationPredicates(dbData.Province, dbData.City, dbData.Area, dbData.Street, 0, core.Operator_EQ)...).
			All(l.ctx)
	}
	if err != nil {
		return nil, hander.HandleEntErr(err, in)
	}
	resp := &core.DistrictTree{
		Tree: make([]*core.DistrictInfo, 0),
	}

	// 树根
	for _, v := range all {
		if v.Level == 1 {
			resp.Tree = append(resp.Tree, l.svcCtx.Convert.ConvertDistrictRpc(l.ctx, v))
		}
	}
	l.makeTree(all, resp.Tree)

	return resp, nil
}

func (l *GetDistrictTreeLogic) makeTree(dataList []*ent.District, nodes []*core.DistrictInfo) {
	for _, node := range nodes {
		node.Children = l.findChildren(dataList, node)
	}
}

func (l *GetDistrictTreeLogic) findChildren(dataList []*ent.District, node *core.DistrictInfo) []*core.DistrictInfo {
	resp := make([]*core.DistrictInfo, 0)
	for _, v := range dataList {
		// 跳一个层级是由于有直辖市的存在
		if v.Level != node.Level+1 && v.Level != node.Level+2 {
			continue
		}
		if v.Province != node.Province {
			continue
		}
		if node.City != "" && node.City != v.City {
			continue
		}
		if node.Area != "" && node.Area != v.Area {
			continue
		}
		child := l.svcCtx.Convert.ConvertDistrictRpc(l.ctx, v)
		if child.Level < 3 || child.Street == "" {
			child.Children = l.findChildren(dataList, child)
		}

		resp = append(resp, child)
	}

	return resp
}
