package repository

import (
	"errors"

	"hyapp-admin-server/internal/model"

	"gorm.io/gorm"
)

func (s *Store) MenusForPermissions(permissionCodes []string) ([]model.Menu, error) {
	var menus []model.Menu
	query := s.db.Where("visible = ?", true).Order("sort DESC, id ASC")
	if len(permissionCodes) > 0 {
		query = query.Where("permission_code = '' OR permission_code IN ?", permissionCodes)
	} else {
		// Empty permission sets may still see structural parent rows, but never rows bound to protected pages.
		query = query.Where("permission_code = ''")
	}
	err := query.Find(&menus).Error
	return menus, err
}

func (s *Store) ListMenus() ([]model.Menu, error) {
	var menus []model.Menu
	err := s.db.Order("sort DESC, id ASC").Find(&menus).Error
	return menus, err
}

func (s *Store) CreateMenu(menu *model.Menu) error {
	normalized, err := normalizeMenu(*menu)
	if err != nil {
		return err
	}
	*menu = normalized
	return s.db.Create(menu).Error
}

func (s *Store) UpdateMenu(id uint, patch model.Menu) (*model.Menu, error) {
	normalized, err := normalizeMenu(patch)
	if err != nil {
		return nil, err
	}

	var menu model.Menu
	if err := s.db.First(&menu, id).Error; err != nil {
		return nil, err
	}
	if normalized.ParentID != nil && *normalized.ParentID == id {
		return nil, errors.New("menu cannot be its own parent")
	}

	// 菜单字段直接影响前端路由和权限入口，更新时保持 code/path/permission_code 同步落库。
	updates := map[string]any{
		"parent_id":       normalized.ParentID,
		"title":           normalized.Title,
		"code":            normalized.Code,
		"path":            normalized.Path,
		"icon":            normalized.Icon,
		"permission_code": normalized.PermissionCode,
		"sort":            normalized.Sort,
		"visible":         normalized.Visible,
	}
	if err := s.db.Model(&menu).Updates(updates).Error; err != nil {
		return nil, err
	}
	if err := s.db.First(&menu, id).Error; err != nil {
		return nil, err
	}
	return &menu, nil
}

func (s *Store) DeleteMenu(id uint) error {
	var children int64
	if err := s.db.Model(&model.Menu{}).Where("parent_id = ?", id).Count(&children).Error; err != nil {
		return err
	}
	if children > 0 {
		return errors.New("menu has children")
	}
	return s.db.Delete(&model.Menu{}, id).Error
}

func (s *Store) UpdateMenuVisible(id uint, visible bool) (*model.Menu, error) {
	var menu model.Menu
	if err := s.db.First(&menu, id).Error; err != nil {
		return nil, err
	}
	if err := s.db.Model(&menu).Update("visible", visible).Error; err != nil {
		return nil, err
	}
	if err := s.db.First(&menu, id).Error; err != nil {
		return nil, err
	}
	return &menu, nil
}

func (s *Store) SortMenus(items []MenuSortItem) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		for _, item := range items {
			if item.ID == 0 {
				return errors.New("invalid menu id")
			}
			// 排序只更新 sort 字段，避免拖拽排序误改路由、权限码等关键入口字段。
			if err := tx.Model(&model.Menu{}).Where("id = ?", item.ID).Update("sort", item.Sort).Error; err != nil {
				return err
			}
		}
		return nil
	})
}
