package system

import (
	"errors"
	"strconv"

	"kra/internal/biz/system"
	"kra/internal/conf"
	"kra/internal/server/middleware"

	kerrors "github.com/go-kratos/kratos/v2/errors"
	"github.com/go-kratos/kratos/v2/transport/http"
)

// CasbinService Casbin服务
type CasbinService struct {
	casbinRepo    system.CasbinRepo
	authUc        *system.AuthorityUsecase
	apiUc         *system.ApiUsecase
	useStrictAuth bool
}

// NewCasbinService 创建Casbin服务
func NewCasbinService(casbinRepo system.CasbinRepo, authUc *system.AuthorityUsecase, apiUc *system.ApiUsecase, useStrictAuth conf.UseStrictAuth) *CasbinService {
	return &CasbinService{
		casbinRepo:    casbinRepo,
		authUc:        authUc,
		apiUc:         apiUc,
		useStrictAuth: bool(useStrictAuth),
	}
}

// UpdateCasbinRequest 更新Casbin请求
type UpdateCasbinRequest struct {
	AuthorityId uint                `json:"authorityId"`
	CasbinInfos []system.CasbinRule `json:"casbinInfos"`
}

// PolicyPathResponse 权限路径响应
type PolicyPathResponse struct {
	Paths []system.CasbinRule `json:"paths"`
}

// GetPolicyPathRequest 获取权限路径请求
type GetPolicyPathRequest struct {
	AuthorityId uint `json:"authorityId"`
}

// UpdateCasbin 更新Casbin权限
func (s *CasbinService) UpdateCasbin(ctx http.Context, adminAuthorityID uint, req *UpdateCasbinRequest) error {
	// 检查权限
	if err := s.authUc.CheckAuthorityIDAuth(ctx, adminAuthorityID, req.AuthorityId); err != nil {
		return err
	}

	// 严格模式下检查API权限
	if s.useStrictAuth {
		apis, err := s.apiUc.GetAllApis(ctx, adminAuthorityID)
		if err != nil {
			return err
		}
		for _, info := range req.CasbinInfos {
			hasApi := false
			for _, api := range apis {
				if api.Path == info.Path && api.Method == info.Method {
					hasApi = true
					break
				}
			}
			if !hasApi {
				return errors.New("存在api不在权限列表中")
			}
		}
	}

	return s.casbinRepo.UpdateCasbin(adminAuthorityID, req.AuthorityId, req.CasbinInfos)
}

// GetPolicyPathByAuthorityId 获取权限列表
func (s *CasbinService) GetPolicyPathByAuthorityId(authorityId uint) []system.CasbinRule {
	return s.casbinRepo.GetPolicyPathByAuthorityId(authorityId)
}

// RegisterRoutes 注册路由
func (s *CasbinService) RegisterRoutes(rg *RouterGroup) {
	// 私有路由 + 操作记录（写操作）
	rg.PrivateWithRecord.POST("/casbin/updateCasbin", s.handleUpdateCasbin)

	// 私有路由（读操作，不记录）
	rg.Private.POST("/casbin/getPolicyPathByAuthorityId", s.handleGetPolicyPath)
}

func (s *CasbinService) handleUpdateCasbin(ctx http.Context) error {
	var req UpdateCasbinRequest
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	if req.AuthorityId == 0 {
		return kerrors.BadRequest("INVALID_AUTHORITY", "角色ID不能为空")
	}
	adminAuthorityID := middleware.GetAuthorityID(ctx)
	if adminAuthorityID == 0 {
		return kerrors.Unauthorized("UNAUTHORIZED", "请先登录")
	}
	if err := s.UpdateCasbin(ctx, adminAuthorityID, &req); err != nil {
		return kerrors.InternalServer("UPDATE_ERROR", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "更新成功"})
}

func (s *CasbinService) handleGetPolicyPath(ctx http.Context) error {
	var req GetPolicyPathRequest
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	if req.AuthorityId == 0 {
		return kerrors.BadRequest("INVALID_AUTHORITY", "角色ID不能为空")
	}
	paths := s.GetPolicyPathByAuthorityId(req.AuthorityId)
	return ctx.Result(200, map[string]any{
		"code": 0,
		"msg":  "获取成功",
		"data": PolicyPathResponse{Paths: paths},
	})
}

// 辅助函数
func uintToStr(n uint) string {
	return strconv.FormatUint(uint64(n), 10)
}
