package system

import (
	"context"

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

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

// MenuService 菜单服务
type MenuService struct {
	uc *system.MenuUsecase
}

// NewMenuService 创建菜单服务
func NewMenuService(uc *system.MenuUsecase) *MenuService {
	return &MenuService{uc: uc}
}

// MenuInfo 菜单信息
type MenuInfo struct {
	ID          uint             `json:"ID"`
	ParentId    uint             `json:"parentId"`
	Path        string           `json:"path"`
	Name        string           `json:"name"`
	Hidden      bool             `json:"hidden"`
	Component   string           `json:"component"`
	Sort        int              `json:"sort"`
	Meta        MenuMeta         `json:"meta"`
	AuthorityId uint             `json:"authorityId,omitempty"`
	MenuId      uint             `json:"menuId,omitempty"`
	Parameters  []*MenuParamInfo `json:"parameters,omitempty"`
	MenuBtn     []*MenuBtnInfo   `json:"menuBtn,omitempty"`
	Btns        map[string]uint  `json:"btns,omitempty"`
	Children    []*MenuInfo      `json:"children,omitempty"`
}

// MenuMeta 菜单元信息
type MenuMeta struct {
	ActiveName     string `json:"activeName"`
	KeepAlive      bool   `json:"keepAlive"`
	DefaultMenu    bool   `json:"defaultMenu"`
	Title          string `json:"title"`
	Icon           string `json:"icon"`
	CloseTab       bool   `json:"closeTab"`
	TransitionType string `json:"transitionType"`
}

// MenuParamInfo 菜单参数信息
type MenuParamInfo struct {
	ID            uint   `json:"ID"`
	SysBaseMenuID uint   `json:"sysBaseMenuId"`
	Type          string `json:"type"`
	Key           string `json:"key"`
	Value         string `json:"value"`
}

// MenuBtnInfo 菜单按钮信息
type MenuBtnInfo struct {
	ID            uint   `json:"ID"`
	SysBaseMenuID uint   `json:"sysBaseMenuId"`
	Name          string `json:"name"`
	Desc          string `json:"desc"`
}

// BaseMenuRequest 基础菜单请求
type BaseMenuRequest struct {
	ID         uint             `json:"ID"`
	ParentId   uint             `json:"parentId"`
	Path       string           `json:"path"`
	Name       string           `json:"name"`
	Hidden     bool             `json:"hidden"`
	Component  string           `json:"component"`
	Sort       int              `json:"sort"`
	Meta       MenuMeta         `json:"meta"`
	Parameters []*MenuParamInfo `json:"parameters"`
	MenuBtn    []*MenuBtnInfo   `json:"menuBtn"`
}

// GetMenu 获取用户动态路由
func (s *MenuService) GetMenu(ctx context.Context, authorityId uint) ([]*MenuInfo, error) {
	menus, err := s.uc.GetMenuTree(ctx, authorityId)
	if err != nil {
		return nil, err
	}
	return toMenuInfoList(menus), nil
}

// GetBaseMenuTree 获取基础菜单树
func (s *MenuService) GetBaseMenuTree(ctx context.Context, authorityId uint) ([]*MenuInfo, error) {
	menus, err := s.uc.GetBaseMenuTree(ctx, authorityId)
	if err != nil {
		return nil, err
	}
	return toBaseMenuInfoList(menus), nil
}

// GetMenuList 获取菜单列表
func (s *MenuService) GetMenuList(ctx context.Context, authorityId uint) ([]*MenuInfo, error) {
	menus, err := s.uc.GetInfoList(ctx, authorityId)
	if err != nil {
		return nil, err
	}
	return toBaseMenuInfoList(menus), nil
}

// AddBaseMenu 添加基础菜单
func (s *MenuService) AddBaseMenu(ctx context.Context, req *BaseMenuRequest) error {
	menu := toBaseMenu(req)
	return s.uc.AddBaseMenu(ctx, menu)
}

// UpdateBaseMenu 更新基础菜单
func (s *MenuService) UpdateBaseMenu(ctx context.Context, req *BaseMenuRequest) error {
	menu := toBaseMenu(req)
	return s.uc.UpdateBaseMenu(ctx, menu)
}

// DeleteBaseMenu 删除基础菜单
func (s *MenuService) DeleteBaseMenu(ctx context.Context, id uint) error {
	return s.uc.DeleteBaseMenu(ctx, id)
}

// GetBaseMenuById 根据ID获取基础菜单
func (s *MenuService) GetBaseMenuById(ctx context.Context, id uint) (*MenuInfo, error) {
	menu, err := s.uc.GetBaseMenuById(ctx, id)
	if err != nil {
		return nil, err
	}
	return toBaseMenuInfo(menu), nil
}

// AddMenuAuthorityRequest 添加菜单权限请求
type AddMenuAuthorityRequest struct {
	AuthorityId uint               `json:"authorityId"`
	Menus       []*BaseMenuRequest `json:"menus"`
}

// AddMenuAuthority 添加菜单权限
func (s *MenuService) AddMenuAuthority(ctx context.Context, adminAuthorityID uint, req *AddMenuAuthorityRequest) error {
	menus := make([]*system.BaseMenu, len(req.Menus))
	for i, m := range req.Menus {
		menus[i] = toBaseMenu(m)
	}
	return s.uc.AddMenuAuthority(ctx, menus, adminAuthorityID, req.AuthorityId)
}

// GetMenuAuthority 获取角色菜单权限
func (s *MenuService) GetMenuAuthority(ctx context.Context, authorityId uint) ([]*MenuInfo, error) {
	menus, err := s.uc.GetMenuAuthority(ctx, authorityId)
	if err != nil {
		return nil, err
	}
	return toMenuInfoList(menus), nil
}

// 转换函数
func toBaseMenu(req *BaseMenuRequest) *system.BaseMenu {
	menu := &system.BaseMenu{
		ID:             req.ID,
		ParentId:       req.ParentId,
		Path:           req.Path,
		Name:           req.Name,
		Hidden:         req.Hidden,
		Component:      req.Component,
		Sort:           req.Sort,
		ActiveName:     req.Meta.ActiveName,
		KeepAlive:      req.Meta.KeepAlive,
		DefaultMenu:    req.Meta.DefaultMenu,
		Title:          req.Meta.Title,
		Icon:           req.Meta.Icon,
		CloseTab:       req.Meta.CloseTab,
		TransitionType: req.Meta.TransitionType,
	}

	if len(req.Parameters) > 0 {
		menu.Parameters = make([]*system.MenuParameter, len(req.Parameters))
		for i, p := range req.Parameters {
			menu.Parameters[i] = &system.MenuParameter{
				ID:            p.ID,
				SysBaseMenuID: p.SysBaseMenuID,
				Type:          p.Type,
				Key:           p.Key,
				Value:         p.Value,
			}
		}
	}

	if len(req.MenuBtn) > 0 {
		menu.MenuBtn = make([]*system.MenuBtn, len(req.MenuBtn))
		for i, b := range req.MenuBtn {
			menu.MenuBtn[i] = &system.MenuBtn{
				ID:            b.ID,
				SysBaseMenuID: b.SysBaseMenuID,
				Name:          b.Name,
				Desc:          b.Desc,
			}
		}
	}

	return menu
}

func toMenuInfoList(menus []*system.Menu) []*MenuInfo {
	if menus == nil {
		return []*MenuInfo{}
	}
	result := make([]*MenuInfo, len(menus))
	for i, m := range menus {
		result[i] = toMenuInfo(m)
	}
	return result
}

func toMenuInfo(m *system.Menu) *MenuInfo {
	info := &MenuInfo{
		ID:          m.ID,
		ParentId:    m.ParentId,
		Path:        m.Path,
		Name:        m.Name,
		Hidden:      m.Hidden,
		Component:   m.Component,
		Sort:        m.Sort,
		AuthorityId: m.AuthorityId,
		MenuId:      m.MenuId,
		Btns:        m.Btns,
		Meta: MenuMeta{
			ActiveName:     m.ActiveName,
			KeepAlive:      m.KeepAlive,
			DefaultMenu:    m.DefaultMenu,
			Title:          m.Title,
			Icon:           m.Icon,
			CloseTab:       m.CloseTab,
			TransitionType: m.TransitionType,
		},
	}

	if len(m.Parameters) > 0 {
		info.Parameters = make([]*MenuParamInfo, len(m.Parameters))
		for i, p := range m.Parameters {
			info.Parameters[i] = &MenuParamInfo{
				ID:            p.ID,
				SysBaseMenuID: p.SysBaseMenuID,
				Type:          p.Type,
				Key:           p.Key,
				Value:         p.Value,
			}
		}
	}

	if len(m.Children) > 0 {
		info.Children = toMenuInfoList(m.Children)
	}

	return info
}

func toBaseMenuInfoList(menus []*system.BaseMenu) []*MenuInfo {
	if menus == nil {
		return []*MenuInfo{}
	}
	result := make([]*MenuInfo, len(menus))
	for i, m := range menus {
		result[i] = toBaseMenuInfo(m)
	}
	return result
}

func toBaseMenuInfo(m *system.BaseMenu) *MenuInfo {
	info := &MenuInfo{
		ID:        m.ID,
		ParentId:  m.ParentId,
		Path:      m.Path,
		Name:      m.Name,
		Hidden:    m.Hidden,
		Component: m.Component,
		Sort:      m.Sort,
		Meta: MenuMeta{
			ActiveName:     m.ActiveName,
			KeepAlive:      m.KeepAlive,
			DefaultMenu:    m.DefaultMenu,
			Title:          m.Title,
			Icon:           m.Icon,
			CloseTab:       m.CloseTab,
			TransitionType: m.TransitionType,
		},
	}

	if len(m.Parameters) > 0 {
		info.Parameters = make([]*MenuParamInfo, len(m.Parameters))
		for i, p := range m.Parameters {
			info.Parameters[i] = &MenuParamInfo{
				ID:            p.ID,
				SysBaseMenuID: p.SysBaseMenuID,
				Type:          p.Type,
				Key:           p.Key,
				Value:         p.Value,
			}
		}
	}

	if len(m.MenuBtn) > 0 {
		info.MenuBtn = make([]*MenuBtnInfo, len(m.MenuBtn))
		for i, b := range m.MenuBtn {
			info.MenuBtn[i] = &MenuBtnInfo{
				ID:            b.ID,
				SysBaseMenuID: b.SysBaseMenuID,
				Name:          b.Name,
				Desc:          b.Desc,
			}
		}
	}

	if len(m.Children) > 0 {
		info.Children = toBaseMenuInfoList(m.Children)
	}

	return info
}

// RegisterRoutes 注册路由
func (s *MenuService) RegisterRoutes(rg *RouterGroup) {
	// 私有路由 + 操作记录（写操作）
	rg.PrivateWithRecord.POST("/menu/addBaseMenu", s.handleAddBaseMenu)
	rg.PrivateWithRecord.POST("/menu/addMenuAuthority", s.handleAddMenuAuthority)
	rg.PrivateWithRecord.POST("/menu/deleteBaseMenu", s.handleDeleteBaseMenu)
	rg.PrivateWithRecord.POST("/menu/updateBaseMenu", s.handleUpdateBaseMenu)

	// 私有路由（读操作，不记录）
	rg.Private.POST("/menu/getMenu", s.handleGetMenu)
	rg.Private.POST("/menu/getMenuList", s.handleGetMenuList)
	rg.Private.POST("/menu/getBaseMenuTree", s.handleGetBaseMenuTree)
	rg.Private.POST("/menu/getMenuAuthority", s.handleGetMenuAuthority)
	rg.Private.POST("/menu/getBaseMenuById", s.handleGetBaseMenuById)
}

// HTTP Handlers
func (s *MenuService) handleGetMenu(ctx http.Context) error {
	authorityId := middleware.GetAuthorityID(ctx)
	menus, err := s.GetMenu(ctx, authorityId)
	if err != nil {
		return errors.InternalServer("GET_MENU_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "获取成功", "data": map[string]any{"menus": menus}})
}

func (s *MenuService) handleGetBaseMenuTree(ctx http.Context) error {
	authorityId := middleware.GetAuthorityID(ctx)
	menus, err := s.GetBaseMenuTree(ctx, authorityId)
	if err != nil {
		return errors.InternalServer("GET_MENU_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "获取成功", "data": map[string]any{"menus": menus}})
}

func (s *MenuService) handleGetMenuList(ctx http.Context) error {
	authorityId := middleware.GetAuthorityID(ctx)
	menus, err := s.GetMenuList(ctx, authorityId)
	if err != nil {
		return errors.InternalServer("GET_MENU_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "获取成功", "data": menus})
}

func (s *MenuService) handleAddBaseMenu(ctx http.Context) error {
	var req BaseMenuRequest
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	if err := s.AddBaseMenu(ctx, &req); err != nil {
		return errors.BadRequest("ADD_MENU_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "添加成功"})
}

func (s *MenuService) handleUpdateBaseMenu(ctx http.Context) error {
	var req BaseMenuRequest
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	if err := s.UpdateBaseMenu(ctx, &req); err != nil {
		return errors.BadRequest("UPDATE_MENU_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "更新成功"})
}

func (s *MenuService) handleDeleteBaseMenu(ctx http.Context) error {
	var req struct {
		ID uint `json:"ID"`
	}
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	if err := s.DeleteBaseMenu(ctx, req.ID); err != nil {
		return errors.BadRequest("DELETE_MENU_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "删除成功"})
}

func (s *MenuService) handleGetBaseMenuById(ctx http.Context) error {
	var req struct {
		ID uint `json:"ID"`
	}
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	menu, err := s.GetBaseMenuById(ctx, req.ID)
	if err != nil {
		return errors.NotFound("MENU_NOT_FOUND", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "获取成功", "data": map[string]any{"menu": menu}})
}

func (s *MenuService) handleAddMenuAuthority(ctx http.Context) error {
	var req AddMenuAuthorityRequest
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	adminAuthorityID := middleware.GetAuthorityID(ctx)
	if err := s.AddMenuAuthority(ctx, adminAuthorityID, &req); err != nil {
		return errors.BadRequest("ADD_AUTHORITY_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "添加成功"})
}

func (s *MenuService) handleGetMenuAuthority(ctx http.Context) error {
	var req struct {
		AuthorityId uint `json:"authorityId"`
	}
	if err := ctx.Bind(&req); err != nil {
		return err
	}
	menus, err := s.GetMenuAuthority(ctx, req.AuthorityId)
	if err != nil {
		return errors.InternalServer("GET_AUTHORITY_FAILED", err.Error())
	}
	return ctx.Result(200, map[string]any{"code": 0, "msg": "获取成功", "data": map[string]any{"menus": menus}})
}
