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/ent/predicate"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/internal/utils"
	"git.noahlan.cn/n-admin/n-admin-server/rpc/core/internal/utils/hander"
	"strings"

	"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 GetDistrictListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

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

func (l *GetDistrictListLogic) GetDistrictList(in *core.DistrictReq) (*core.DistrictListResp, error) {
	var predicates []predicate.District
	switch in.QueryType {
	case core.DistrictQueryType_Children:
		if in.ParentCode == "" {
			// 参数为空时，查询第一级
			predicates = relationPredicates("", "", "", "", 1, core.Operator_EQ)
		} else {
			first, err := l.svcCtx.DB.District.Query().Where(district.CodeEQ(in.ParentCode)).First(l.ctx)
			if err != nil {
				return nil, hander.HandleEntErr(err, in)
			}
			lv := first.Level + 1
			if first.Level == 1 && strings.Contains(first.Name, "市") {
				// 直辖市 Directly
				lv = lv + 1
			}
			predicates = relationPredicates(first.Province, first.City, first.Area, first.Street, lv, core.Operator_EQ)
		}
	case core.DistrictQueryType_ChildrenByLevel:
		if in.ParentCode != "" {
			// 参数为空时，查询指定级别
			predicates = relationPredicates("", "", "", "", in.Level, core.Operator_EQ)
		} else {
			first, err := l.svcCtx.DB.District.Query().Where(district.CodeEQ(in.ParentCode)).First(l.ctx)
			if err != nil {
				return nil, hander.HandleEntErr(err, in)
			}
			lv := first.Level + in.Level
			if first.Level == 1 && strings.Contains(first.Name, "市") {
				// 直辖市 Directly
				lv = lv + 1
			}
			predicates = relationPredicates(first.Province, first.City, first.Area, first.Street, lv, core.Operator_EQ)
		}
	case core.DistrictQueryType_Parents:
		first, err := l.svcCtx.DB.District.Query().Where(district.CodeEQ(in.Code)).First(l.ctx)
		if err != nil {
			return nil, hander.HandleEntErr(err, in)
		}
		predicates = relationPredicates(first.Province, first.City, first.Area, first.Street, first.Level, core.Operator_LTE)
	case core.DistrictQueryType_Normal:
		fallthrough
	default:
		if in.Code != "" {
			predicates = append(predicates, district.CodeEQ(in.Code))
		}
		if in.Province != "" {
			predicates = append(predicates, district.ProvinceEQ(in.Province))
		}
		if in.City != "" {
			predicates = append(predicates, district.CityEQ(in.City))
		}
		if in.Area != "" {
			predicates = append(predicates, district.AreaEQ(in.Area))
		}
		if in.Street != "" {
			predicates = append(predicates, district.StreetEQ(in.Street))
		}
		if in.Level != 0 {
			predicates = append(predicates, district.LevelEQ(in.Level))
		}
	}

	var (
		pagination *core.Pagination
		list       []*ent.District
		err        error
	)

	query := l.svcCtx.DB.District.Query().Where(predicates...)
	if in.Page != nil {
		result, pageErr := query.Page(l.ctx, in.Page.Current, in.Page.Size)
		if pageErr == nil {
			pagination = utils.ConvertPaginationDb(result.PageDetails)
			list = result.List
		} else {
			err = pageErr
		}
	} else {
		list, err = query.All(l.ctx)
	}
	if err != nil {
		return nil, hander.HandleEntErr(err, in)
	}

	resp := &core.DistrictListResp{
		Page: pagination,
		Data: make([]*core.DistrictInfo, len(list)),
	}
	for i, v := range list {
		resp.Data[i] = l.svcCtx.Convert.ConvertDistrictRpc(l.ctx, v)
	}

	return resp, nil
}
