package admin_role

import (
	"context"
	"strings"
	"sync"
	"time"

	"bdrp-server/app/main/api/internal/svc"
	"bdrp-server/app/main/api/internal/types"
	"bdrp-server/app/main/model"

	"github.com/Masterminds/squirrel"
	"github.com/samber/lo"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/mr"
)

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

func NewGetRoleListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRoleListLogic {
	return &GetRoleListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}
func (l *GetRoleListLogic) GetRoleList(req *types.GetRoleListReq) (resp *types.GetRoleListResp, err error) {
	resp = &types.GetRoleListResp{
		Items: make([]types.RoleListItem, 0),
		Total: 0,
	}

	// 构建查询条件
	builder := l.svcCtx.AdminRoleModel.SelectBuilder()
	builder = applyRoleListFilters(builder, req)

	// 设置分页
	offset := (req.Page - 1) * req.PageSize
	builder = builder.OrderBy("sort ASC").Limit(uint64(req.PageSize)).Offset(uint64(offset))

	// 使用MapReduceVoid并发获取总数和列表数据
	var roles []*model.AdminRole
	var total int64
	var mutex sync.Mutex
	var wg sync.WaitGroup

	mr.MapReduceVoid(func(source chan<- interface{}) {
		source <- 1 // 获取角色列表
		source <- 2 // 获取总数
	}, func(item interface{}, writer mr.Writer[*model.AdminRole], cancel func(error)) {
		taskType := item.(int)
		wg.Add(1)
		defer wg.Done()

		if taskType == 1 {
			result, err := l.svcCtx.AdminRoleModel.FindAll(l.ctx, builder, "id DESC")
			if err != nil {
				cancel(err)
				return
			}
			mutex.Lock()
			roles = result
			mutex.Unlock()
		} else if taskType == 2 {
			countBuilder := l.svcCtx.AdminRoleModel.SelectBuilder()
			countBuilder = applyRoleListFilters(countBuilder, req)

			count, err := l.svcCtx.AdminRoleModel.FindCount(l.ctx, countBuilder, "id")
			if err != nil {
				cancel(err)
				return
			}
			mutex.Lock()
			total = count
			mutex.Unlock()
		}
	}, func(pipe <-chan *model.AdminRole, cancel func(error)) {
		// 不需要处理pipe中的数据
	})

	wg.Wait()

	// 并发获取每个角色的菜单ID
	var roleItems []types.RoleListItem
	var roleItemsMutex sync.Mutex

	mr.MapReduceVoid(func(source chan<- interface{}) {
		for _, role := range roles {
			source <- role
		}
	}, func(item interface{}, writer mr.Writer[[]int64], cancel func(error)) {
		role := item.(*model.AdminRole)

		// 获取角色关联的菜单ID
		builder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().
			Where("role_id = ?", role.Id)
		menus, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, builder, "id ASC")
		if err != nil {
			cancel(err)
			return
		}
		menuIds := lo.Map(menus, func(item *model.AdminRoleMenu, _ int) int64 {
			return item.MenuId
		})

		writer.Write(menuIds)
	}, func(pipe <-chan []int64, cancel func(error)) {
		for _, role := range roles {
			menuIds := <-pipe
			item := types.RoleListItem{
				Id:          role.Id,
				RoleName:    role.RoleName,
				RoleCode:    role.RoleCode,
				Description: role.Description,
				Status:      role.Status,
				Sort:        role.Sort,
				CreateTime:  role.CreateTime.Format("2006-01-02 15:04:05"),
				MenuIds:     menuIds,
			}
			roleItemsMutex.Lock()
			roleItems = append(roleItems, item)
			roleItemsMutex.Unlock()
		}
	})

	resp.Items = roleItems
	resp.Total = total

	return resp, nil
}

func applyRoleListFilters(builder squirrel.SelectBuilder, req *types.GetRoleListReq) squirrel.SelectBuilder {
	roleName := strings.TrimSpace(req.RoleName)
	if roleName == "" {
		roleName = strings.TrimSpace(req.Name)
	}
	if roleName != "" {
		builder = builder.Where("role_name LIKE ?", "%"+roleName+"%")
	}

	roleCode := strings.TrimSpace(req.RoleCode)
	if roleCode == "" {
		roleCode = strings.TrimSpace(req.Code)
	}
	if roleCode != "" {
		builder = builder.Where("role_code LIKE ?", "%"+roleCode+"%")
	}

	description := strings.TrimSpace(req.Description)
	if description != "" {
		builder = builder.Where("description LIKE ?", "%"+description+"%")
	}

	if req.Status != -1 {
		builder = builder.Where("status = ?", req.Status)
	}

	if startTime, ok := parseRoleListTime(req.StartTime, false); ok {
		builder = builder.Where("create_time >= ?", startTime)
	}
	if endTime, ok := parseRoleListTime(req.EndTime, true); ok {
		builder = builder.Where("create_time <= ?", endTime)
	}

	return builder
}

func parseRoleListTime(raw string, isEnd bool) (time.Time, bool) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return time.Time{}, false
	}

	for _, layout := range []string{"2006-01-02 15:04:05", "2006-01-02", time.RFC3339} {
		if t, err := time.Parse(layout, raw); err == nil {
			if layout == "2006-01-02" && isEnd {
				t = t.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
			}
			return t, true
		}
	}
	return time.Time{}, false
}
