package system

import (
	"context"
	"errors"

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

	"gorm.io/gorm"
)

type authorityRepo struct {
	db *gorm.DB
}

// NewAuthorityRepo 创建角色仓储
func NewAuthorityRepo(db *gorm.DB) system.AuthorityRepo {
	return &authorityRepo{db: db}
}

func (r *authorityRepo) Create(ctx context.Context, auth *system.Authority) error {
	m := &model.SysAuthority{
		AuthorityID:   int64(auth.AuthorityId),
		AuthorityName: auth.AuthorityName,
		DefaultRouter: auth.DefaultRouter,
	}
	if auth.ParentId != nil {
		m.ParentID = int64(*auth.ParentId)
	}
	return r.db.WithContext(ctx).Create(m).Error
}

func (r *authorityRepo) Update(ctx context.Context, auth *system.Authority) error {
	updates := map[string]any{
		"authority_name": auth.AuthorityName,
		"default_router": auth.DefaultRouter,
	}
	if auth.ParentId != nil {
		updates["parent_id"] = *auth.ParentId
	}
	return r.db.WithContext(ctx).Model(&model.SysAuthority{}).
		Where("authority_id = ?", auth.AuthorityId).
		Updates(updates).Error
}

func (r *authorityRepo) Delete(ctx context.Context, authorityId uint) error {
	return r.db.WithContext(ctx).Unscoped().
		Where("authority_id = ?", authorityId).
		Delete(&model.SysAuthority{}).Error
}

func (r *authorityRepo) FindByID(ctx context.Context, authorityId uint) (*system.Authority, error) {
	m, err := query.SysAuthority.WithContext(ctx).
		Where(query.SysAuthority.AuthorityID.Eq(int64(authorityId))).First()
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return toBizAuthority(m), nil
}

func (r *authorityRepo) FindByIDWithDataAuthority(ctx context.Context, authorityId uint) (*system.AuthorityFull, error) {
	m, err := query.SysAuthority.WithContext(ctx).
		Where(query.SysAuthority.AuthorityID.Eq(int64(authorityId))).First()
	if err != nil {
		return nil, err
	}

	// 获取数据权限
	var dataAuthIds []model.SysDataAuthorityID
	r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).Find(&dataAuthIds)

	var dataAuthorities []*system.Authority
	for _, da := range dataAuthIds {
		auth, _ := r.FindByID(ctx, uint(da.DataAuthorityIDAuthorityID))
		if auth != nil {
			dataAuthorities = append(dataAuthorities, auth)
		}
	}

	return &system.AuthorityFull{
		Authority:       *toBizAuthority(m),
		DataAuthorityId: dataAuthorities,
	}, nil
}

func (r *authorityRepo) FindByParentID(ctx context.Context, parentId uint) ([]*system.AuthorityFull, error) {
	list, err := query.SysAuthority.WithContext(ctx).
		Where(query.SysAuthority.ParentID.Eq(int64(parentId))).Find()
	if err != nil {
		return nil, err
	}

	result := make([]*system.AuthorityFull, len(list))
	for i, m := range list {
		// 获取数据权限
		var dataAuthIds []model.SysDataAuthorityID
		r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", m.AuthorityID).Find(&dataAuthIds)

		var dataAuthorities []*system.Authority
		for _, da := range dataAuthIds {
			auth, _ := r.FindByID(ctx, uint(da.DataAuthorityIDAuthorityID))
			if auth != nil {
				dataAuthorities = append(dataAuthorities, auth)
			}
		}

		result[i] = &system.AuthorityFull{
			Authority:       *toBizAuthority(m),
			DataAuthorityId: dataAuthorities,
		}
	}
	return result, nil
}

func (r *authorityRepo) FindChildren(ctx context.Context, authorityId uint) ([]*system.AuthorityFull, error) {
	return r.FindByParentID(ctx, authorityId)
}

func (r *authorityRepo) HasUsers(ctx context.Context, authorityId uint) (bool, error) {
	var count int64
	err := r.db.WithContext(ctx).Model(&model.SysUserAuthority{}).
		Where("sys_authority_authority_id = ?", authorityId).Count(&count).Error
	return count > 0, err
}

func (r *authorityRepo) HasChildren(ctx context.Context, authorityId uint) (bool, error) {
	count, err := query.SysAuthority.WithContext(ctx).
		Where(query.SysAuthority.ParentID.Eq(int64(authorityId))).Count()
	return count > 0, err
}

func (r *authorityRepo) GetParentAuthorityID(ctx context.Context, authorityId uint) (uint, error) {
	m, err := query.SysAuthority.WithContext(ctx).
		Where(query.SysAuthority.AuthorityID.Eq(int64(authorityId))).First()
	if err != nil {
		return 0, err
	}
	return uint(m.ParentID), nil
}

func (r *authorityRepo) SetDataAuthority(ctx context.Context, authorityId uint, dataAuthorityIds []uint) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 删除旧的数据权限
		if err := tx.Where("sys_authority_authority_id = ?", authorityId).
			Delete(&model.SysDataAuthorityID{}).Error; err != nil {
			return err
		}

		// 创建新的数据权限
		for _, daId := range dataAuthorityIds {
			da := &model.SysDataAuthorityID{
				SysAuthorityAuthorityID:    int64(authorityId),
				DataAuthorityIDAuthorityID: int64(daId),
			}
			if err := tx.Create(da).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

func (r *authorityRepo) 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 (r *authorityRepo) GetMenuIds(ctx context.Context, authorityId uint) ([]uint, error) {
	var menus []model.SysAuthorityMenu
	if err := r.db.WithContext(ctx).Where("sys_authority_authority_id = ?", authorityId).
		Find(&menus).Error; err != nil {
		return nil, err
	}

	ids := make([]uint, len(menus))
	for i, m := range menus {
		ids[i] = uint(m.SysBaseMenuID)
	}
	return ids, nil
}

func (r *authorityRepo) CopyAuthorityBtns(ctx context.Context, oldAuthorityId, newAuthorityId uint) error {
	var btns []model.SysAuthorityBtn
	if err := r.db.WithContext(ctx).Where("authority_id = ?", oldAuthorityId).
		Find(&btns).Error; err != nil {
		return err
	}

	if len(btns) == 0 {
		return nil
	}

	for i := range btns {
		btns[i].AuthorityID = int64(newAuthorityId)
	}

	return r.db.WithContext(ctx).Create(&btns).Error
}

func (r *authorityRepo) DeleteAuthorityRelations(ctx context.Context, authorityId 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
		}

		// 删除数据权限
		if err := tx.Where("sys_authority_authority_id = ?", authorityId).
			Delete(&model.SysDataAuthorityID{}).Error; err != nil {
			return err
		}

		// 删除用户角色关联
		if err := tx.Where("sys_authority_authority_id = ?", authorityId).
			Delete(&model.SysUserAuthority{}).Error; err != nil {
			return err
		}

		// 删除按钮权限
		if err := tx.Where("authority_id = ?", authorityId).
			Delete(&model.SysAuthorityBtn{}).Error; err != nil {
			return err
		}

		return nil
	})
}

// 转换函数
func toBizAuthority(m *model.SysAuthority) *system.Authority {
	auth := &system.Authority{
		AuthorityId:   uint(m.AuthorityID),
		AuthorityName: m.AuthorityName,
		DefaultRouter: m.DefaultRouter,
	}
	if m.ParentID != 0 {
		parentId := uint(m.ParentID)
		auth.ParentId = &parentId
	}
	return auth
}
