package system

import (
	"context"
	"errors"
	"strconv"

	"kra/internal/biz/system"
	"kra/internal/data/model"

	"gorm.io/gorm"
)

type menuRepo struct {
	db *gorm.DB
}

// NewMenuRepo 创建菜单仓储
func NewMenuRepo(db *gorm.DB) system.MenuRepo {
	return &menuRepo{db: db}
}

// CreateBaseMenu 创建基础菜单
func (r *menuRepo) CreateBaseMenu(ctx context.Context, menu *system.BaseMenu) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 检查name是否重复
		var count int64
		if err := tx.Model(&model.SysBaseMenu{}).Where("name = ?", menu.Name).Count(&count).Error; err != nil {
			return err
		}
		if count > 0 {
			return errors.New("存在重复name，请修改name")
		}

		if menu.ParentId != 0 {
			// 检查父菜单是否存在
			var parentMenu model.SysBaseMenu
			if err := tx.First(&parentMenu, menu.ParentId).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return errors.New("父菜单不存在")
				}
				return err
			}

			// 检查父菜单下现有子菜单数量
			var existingChildrenCount int64
			if err := tx.Model(&model.SysBaseMenu{}).Where("parent_id = ?", menu.ParentId).Count(&existingChildrenCount).Error; err != nil {
				return err
			}

			// 如果父菜单原本是叶子菜单，需要清空其权限分配
			if existingChildrenCount == 0 {
				// 检查父菜单是否被其他角色设置为首页
				var defaultRouterCount int64
				if err := tx.Model(&model.SysAuthority{}).Where("default_router = ?", parentMenu.Name).Count(&defaultRouterCount).Error; err != nil {
					return err
				}
				if defaultRouterCount > 0 {
					return errors.New("父菜单已被其他角色的首页占用，请先释放父菜单的首页权限")
				}

				// 清空父菜单的所有权限分配
				if err := tx.Where("sys_base_menu_id = ?", menu.ParentId).Delete(&model.SysAuthorityMenu{}).Error; err != nil {
					return err
				}
			}
		}

		// 创建菜单
		m := toModelBaseMenu(menu)
		if err := tx.Create(m).Error; err != nil {
			return err
		}

		// 创建参数
		if len(menu.Parameters) > 0 {
			for _, p := range menu.Parameters {
				param := &model.SysBaseMenuParameter{
					SysBaseMenuID: int64(m.ID),
					Type:          p.Type,
					Key:           p.Key,
					Value:         p.Value,
				}
				if err := tx.Create(param).Error; err != nil {
					return err
				}
			}
		}

		// 创建按钮
		if len(menu.MenuBtn) > 0 {
			for _, b := range menu.MenuBtn {
				btn := &model.SysBaseMenuBtn{
					SysBaseMenuID: int64(m.ID),
					Name:          b.Name,
					Desc:          b.Desc,
				}
				if err := tx.Create(btn).Error; err != nil {
					return err
				}
			}
		}

		menu.ID = uint(m.ID)
		return nil
	})
}

// UpdateBaseMenu 更新基础菜单
func (r *menuRepo) UpdateBaseMenu(ctx context.Context, menu *system.BaseMenu) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		var oldMenu model.SysBaseMenu
		if err := tx.Where("id = ?", menu.ID).First(&oldMenu).Error; err != nil {
			return err
		}

		// 检查name是否重复
		if oldMenu.Name != menu.Name {
			var count int64
			if err := tx.Model(&model.SysBaseMenu{}).Where("id <> ? AND name = ?", menu.ID, menu.Name).Count(&count).Error; err != nil {
				return err
			}
			if count > 0 {
				return errors.New("存在相同name修改失败")
			}
		}

		// 删除旧参数和按钮
		if err := tx.Unscoped().Where("sys_base_menu_id = ?", menu.ID).Delete(&model.SysBaseMenuParameter{}).Error; err != nil {
			return err
		}
		if err := tx.Unscoped().Where("sys_base_menu_id = ?", menu.ID).Delete(&model.SysBaseMenuBtn{}).Error; err != nil {
			return err
		}

		// 创建新参数
		if len(menu.Parameters) > 0 {
			for _, p := range menu.Parameters {
				param := &model.SysBaseMenuParameter{
					SysBaseMenuID: int64(menu.ID),
					Type:          p.Type,
					Key:           p.Key,
					Value:         p.Value,
				}
				if err := tx.Create(param).Error; err != nil {
					return err
				}
			}
		}

		// 创建新按钮
		if len(menu.MenuBtn) > 0 {
			for _, b := range menu.MenuBtn {
				btn := &model.SysBaseMenuBtn{
					SysBaseMenuID: int64(menu.ID),
					Name:          b.Name,
					Desc:          b.Desc,
				}
				if err := tx.Create(btn).Error; err != nil {
					return err
				}
			}
		}

		// 更新菜单
		updates := map[string]any{
			"keep_alive":      menu.KeepAlive,
			"close_tab":       menu.CloseTab,
			"default_menu":    menu.DefaultMenu,
			"parent_id":       menu.ParentId,
			"path":            menu.Path,
			"name":            menu.Name,
			"hidden":          menu.Hidden,
			"component":       menu.Component,
			"title":           menu.Title,
			"active_name":     menu.ActiveName,
			"icon":            menu.Icon,
			"sort":            menu.Sort,
			"transition_type": menu.TransitionType,
		}
		return tx.Model(&oldMenu).Updates(updates).Error
	})
}

// DeleteBaseMenu 删除基础菜单
func (r *menuRepo) DeleteBaseMenu(ctx context.Context, id uint) error {
	// 检查是否有子菜单
	var childCount int64
	if err := r.db.WithContext(ctx).Model(&model.SysBaseMenu{}).Where("parent_id = ?", id).Count(&childCount).Error; err != nil {
		return err
	}
	if childCount > 0 {
		return errors.New("此菜单存在子菜单不可删除")
	}

	// 获取菜单信息
	var menu model.SysBaseMenu
	if err := r.db.WithContext(ctx).First(&menu, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("记录不存在")
		}
		return err
	}

	// 检查是否有角色将此菜单作为首页
	var defaultRouterCount int64
	if err := r.db.WithContext(ctx).Model(&model.SysAuthority{}).Where("default_router = ?", menu.Name).Count(&defaultRouterCount).Error; err != nil {
		return err
	}
	if defaultRouterCount > 0 {
		return errors.New("此菜单有角色正在作为首页，不可删除")
	}

	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if err := tx.Delete(&model.SysBaseMenu{}, "id = ?", id).Error; err != nil {
			return err
		}
		if err := tx.Delete(&model.SysBaseMenuParameter{}, "sys_base_menu_id = ?", id).Error; err != nil {
			return err
		}
		if err := tx.Delete(&model.SysBaseMenuBtn{}, "sys_base_menu_id = ?", id).Error; err != nil {
			return err
		}
		if err := tx.Delete(&model.SysAuthorityBtn{}, "sys_menu_id = ?", id).Error; err != nil {
			return err
		}
		if err := tx.Delete(&model.SysAuthorityMenu{}, "sys_base_menu_id = ?", id).Error; err != nil {
			return err
		}
		return nil
	})
}

// FindBaseMenuByID 根据ID获取基础菜单
func (r *menuRepo) FindBaseMenuByID(ctx context.Context, id uint) (*system.BaseMenu, error) {
	var menu model.SysBaseMenu
	if err := r.db.WithContext(ctx).Where("id = ?", id).First(&menu).Error; err != nil {
		return nil, err
	}

	// 获取参数
	var params []model.SysBaseMenuParameter
	r.db.WithContext(ctx).Where("sys_base_menu_id = ?", id).Find(&params)

	// 获取按钮
	var btns []model.SysBaseMenuBtn
	r.db.WithContext(ctx).Where("sys_base_menu_id = ?", id).Find(&btns)

	return toBizBaseMenu(&menu, params, btns), nil
}

// FindBaseMenuByName 根据名称获取基础菜单
func (r *menuRepo) FindBaseMenuByName(ctx context.Context, name string) (*system.BaseMenu, error) {
	var menu model.SysBaseMenu
	if err := r.db.WithContext(ctx).Where("name = ?", name).First(&menu).Error; err != nil {
		return nil, err
	}
	return toBizBaseMenu(&menu, nil, nil), nil
}

// CheckMenuInAuthority 检查菜单是否在角色权限中
func (r *menuRepo) CheckMenuInAuthority(ctx context.Context, authorityId uint, menuName string) (bool, error) {
	// 获取角色的菜单ID列表
	var menuIds []string
	if err := r.db.WithContext(ctx).Model(&model.SysAuthorityMenu{}).
		Where("sys_authority_authority_id = ?", authorityId).
		Pluck("sys_base_menu_id", &menuIds).Error; err != nil {
		return false, err
	}

	if len(menuIds) == 0 {
		return false, nil
	}

	// 检查菜单名称是否在这些菜单中
	var count int64
	if err := r.db.WithContext(ctx).Model(&model.SysBaseMenu{}).
		Where("name = ? AND id IN (?)", menuName, menuIds).
		Count(&count).Error; err != nil {
		return false, err
	}

	return count > 0, nil
}

// FindAllBaseMenus 获取所有基础菜单
func (r *menuRepo) FindAllBaseMenus(ctx context.Context) ([]*system.BaseMenu, error) {
	var menus []model.SysBaseMenu
	if err := r.db.WithContext(ctx).Order("sort").Find(&menus).Error; err != nil {
		return nil, err
	}

	// 获取所有参数
	var allParams []model.SysBaseMenuParameter
	r.db.WithContext(ctx).Find(&allParams)
	paramMap := make(map[int64][]model.SysBaseMenuParameter)
	for _, p := range allParams {
		paramMap[p.SysBaseMenuID] = append(paramMap[p.SysBaseMenuID], p)
	}

	// 获取所有按钮
	var allBtns []model.SysBaseMenuBtn
	r.db.WithContext(ctx).Find(&allBtns)
	btnMap := make(map[int64][]model.SysBaseMenuBtn)
	for _, b := range allBtns {
		btnMap[b.SysBaseMenuID] = append(btnMap[b.SysBaseMenuID], b)
	}

	result := make([]*system.BaseMenu, len(menus))
	for i, m := range menus {
		result[i] = toBizBaseMenu(&m, paramMap[m.ID], btnMap[m.ID])
	}
	return result, nil
}

// FindBaseMenusByIds 根据ID列表获取基础菜单
func (r *menuRepo) FindBaseMenusByIds(ctx context.Context, ids []string) ([]*system.BaseMenu, error) {
	var menus []model.SysBaseMenu
	if err := r.db.WithContext(ctx).Where("id in (?)", ids).Order("sort").Find(&menus).Error; err != nil {
		return nil, err
	}

	// 获取参数
	var allParams []model.SysBaseMenuParameter
	r.db.WithContext(ctx).Where("sys_base_menu_id in (?)", ids).Find(&allParams)
	paramMap := make(map[int64][]model.SysBaseMenuParameter)
	for _, p := range allParams {
		paramMap[p.SysBaseMenuID] = append(paramMap[p.SysBaseMenuID], p)
	}

	// 获取按钮
	var allBtns []model.SysBaseMenuBtn
	r.db.WithContext(ctx).Where("sys_base_menu_id in (?)", ids).Find(&allBtns)
	btnMap := make(map[int64][]model.SysBaseMenuBtn)
	for _, b := range allBtns {
		btnMap[b.SysBaseMenuID] = append(btnMap[b.SysBaseMenuID], b)
	}

	result := make([]*system.BaseMenu, len(menus))
	for i, m := range menus {
		result[i] = toBizBaseMenu(&m, paramMap[m.ID], btnMap[m.ID])
	}
	return result, nil
}

// FindAuthorityMenuIds 获取角色的菜单ID列表
func (r *menuRepo) FindAuthorityMenuIds(ctx context.Context, authorityId uint) ([]string, error) {
	var authorityMenus []model.SysAuthorityMenu
	if err := r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).Find(&authorityMenus).Error; err != nil {
		return nil, err
	}
	menuIds := make([]string, len(authorityMenus))
	for i, am := range authorityMenus {
		menuIds[i] = strconv.FormatInt(am.SysBaseMenuID, 10)
	}
	return menuIds, nil
}

// FindAuthorityBtns 获取角色的按钮权限
func (r *menuRepo) FindAuthorityBtns(ctx context.Context, authorityId uint) ([]*system.AuthorityBtn, error) {
	var btns []model.SysAuthorityBtn
	if err := r.db.WithContext(ctx).Where("authority_id = ?", authorityId).Find(&btns).Error; err != nil {
		return nil, err
	}

	// 获取按钮名称
	var btnIds []int64
	for _, b := range btns {
		btnIds = append(btnIds, b.SysBaseMenuBtnID)
	}

	btnNameMap := make(map[int64]string)
	if len(btnIds) > 0 {
		var menuBtns []model.SysBaseMenuBtn
		r.db.WithContext(ctx).Where("id in (?)", btnIds).Find(&menuBtns)
		for _, mb := range menuBtns {
			btnNameMap[mb.ID] = mb.Name
		}
	}

	result := make([]*system.AuthorityBtn, len(btns))
	for i, b := range btns {
		result[i] = &system.AuthorityBtn{
			AuthorityId:      uint(b.AuthorityID),
			SysMenuID:        uint(b.SysMenuID),
			SysBaseMenuBtnID: uint(b.SysBaseMenuBtnID),
			BtnName:          btnNameMap[b.SysBaseMenuBtnID],
		}
	}
	return result, nil
}

// SetMenuAuthority 设置角色菜单权限
func (r *menuRepo) SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 删除旧权限
		if err := tx.Where("sys_authority_authority_id = ?", authorityId).Delete(&model.SysAuthorityMenu{}).Error; err != nil {
			return err
		}

		// 创建新权限
		for _, menuId := range menuIds {
			am := &model.SysAuthorityMenu{
				SysAuthorityAuthorityID: int64(authorityId),
				SysBaseMenuID:           int64(menuId),
			}
			if err := tx.Create(am).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

// 转换函数
func toModelBaseMenu(m *system.BaseMenu) *model.SysBaseMenu {
	return &model.SysBaseMenu{
		ID:             int64(m.ID),
		ParentID:       int64(m.ParentId),
		Path:           m.Path,
		Name:           m.Name,
		Hidden:         m.Hidden,
		Component:      m.Component,
		Sort:           int64(m.Sort),
		ActiveName:     m.ActiveName,
		KeepAlive:      m.KeepAlive,
		DefaultMenu:    m.DefaultMenu,
		Title:          m.Title,
		Icon:           m.Icon,
		CloseTab:       m.CloseTab,
		TransitionType: m.TransitionType,
	}
}

func toBizBaseMenu(m *model.SysBaseMenu, params []model.SysBaseMenuParameter, btns []model.SysBaseMenuBtn) *system.BaseMenu {
	menu := &system.BaseMenu{
		ID:             uint(m.ID),
		ParentId:       uint(m.ParentID),
		Path:           m.Path,
		Name:           m.Name,
		Hidden:         m.Hidden,
		Component:      m.Component,
		Sort:           int(m.Sort),
		ActiveName:     m.ActiveName,
		KeepAlive:      m.KeepAlive,
		DefaultMenu:    m.DefaultMenu,
		Title:          m.Title,
		Icon:           m.Icon,
		CloseTab:       m.CloseTab,
		TransitionType: m.TransitionType,
	}

	// 转换参数
	if len(params) > 0 {
		menu.Parameters = make([]*system.MenuParameter, len(params))
		for i, p := range params {
			menu.Parameters[i] = &system.MenuParameter{
				ID:            uint(p.ID),
				SysBaseMenuID: uint(p.SysBaseMenuID),
				Type:          p.Type,
				Key:           p.Key,
				Value:         p.Value,
			}
		}
	}

	// 转换按钮
	if len(btns) > 0 {
		menu.MenuBtn = make([]*system.MenuBtn, len(btns))
		for i, b := range btns {
			menu.MenuBtn[i] = &system.MenuBtn{
				ID:            uint(b.ID),
				SysBaseMenuID: uint(b.SysBaseMenuID),
				Name:          b.Name,
				Desc:          b.Desc,
			}
		}
	}

	return menu
}

func ptrInt64(v int64) *int64 {
	return &v
}
