package internal

import (
	"context"
	"strings"

	"github.com/gogf/gf/v2/util/guid"
	"yx-dataset-server/app/errors"
	"yx-dataset-server/app/model"
	"yx-dataset-server/app/schema"
	"yx-dataset-server/library/redis"
	"yx-dataset-server/library/utils"
)

// NewUser 创建User
func NewUser(
	mUser model.IUser,
	mRelation model.IDatasetRelation,
	mTrans model.ITrans,
	mMenu model.IMenu,
	mRoleMenu model.IRoleMenu,
	mDataset model.IDataset,
	mOrganization model.IOrganization,
	mRole model.IRole,
) *User {
	return &User{
		UserModel:     mUser,
		relationModel: mRelation,
		transModel:    mTrans,
		menuModel:     mMenu,
		roleMenuModel: mRoleMenu,
		datasetModel:  mDataset,
		orgModel:      mOrganization,
		roleModel:     mRole,
	}
}

// User 创建User对象
type User struct {
	UserModel     model.IUser
	relationModel model.IDatasetRelation
	transModel    model.ITrans
	menuModel     model.IMenu
	roleMenuModel model.IRoleMenu
	datasetModel  model.IDataset
	orgModel      model.IOrganization
	roleModel     model.IRole
}

// classifyDatasets 按 type 分桶填充
func classifyDatasets(user *schema.User, datasets schema.Datasets) {
	user.Datasets = datasets
	user.PublicDatasets = make(schema.Datasets, 0)
	user.OrgDatasets = make(schema.Datasets, 0)
	user.PersonalDatasets = make(schema.Datasets, 0)
	for _, d := range datasets {
		switch d.Type {
		case schema.DatasetTypePublic:
			user.PublicDatasets = append(user.PublicDatasets, d)
		case schema.DatasetTypeOrg:
			user.OrgDatasets = append(user.OrgDatasets, d)
		case schema.DatasetTypePersonal:
			user.PersonalDatasets = append(user.PersonalDatasets, d)
		}
	}
}

// loadUserDatasets 加载指定用户的可访问知识库并按类型分桶填充
// 特殊规则：系统管理员（root 另行处理于 getRootInfo）——
//
//	可查看全部公共/共享知识库（type=1） + 本人的个人知识库（type=3）
func (a *User) loadUserDatasets(ctx context.Context, user *schema.User) error {
	// 系统管理员：全部公共KB + 本人的个人KB
	if user.RoleId != "" {
		role, err := a.roleModel.Get(ctx, user.RoleId)
		if err != nil {
			return err
		}
		if role != nil && role.Code == RoleCodeSystemAdmin {
			return a.loadAdminDatasets(ctx, user)
		}
	}
	// 其他角色：仅限 DatasetRelation 里显式授权的
	rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{BizId: user.RecordID})
	if err != nil {
		return err
	}
	if len(rel.Data) == 0 {
		classifyDatasets(user, schema.Datasets{})
		return nil
	}
	datasets, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
	if err != nil {
		return err
	}
	classifyDatasets(user, datasets.Data)
	return nil
}

// loadAdminDatasets 为 root / 系统管理员加载：全部公共KB + 本人个人KB
func (a *User) loadAdminDatasets(ctx context.Context, user *schema.User) error {
	public, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{Type: schema.DatasetTypePublic})
	if err != nil {
		return err
	}

	all := make(schema.Datasets, 0, len(public.Data))
	all = append(all, public.Data...)

	// 本人个人知识库（通过 DatasetRelation 绑定）
	rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{
		BizId: user.RecordID,
		Type:  schema.DatasetTypePersonal,
	})
	if err != nil {
		return err
	}
	if len(rel.Data) > 0 {
		personal, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
		if err != nil {
			return err
		}
		all = append(all, personal.Data...)
	}
	classifyDatasets(user, all)
	return nil
}

// Query 查询数据
func (a *User) Query(ctx context.Context, params schema.UserQueryParam, opts ...schema.UserOptions) (*schema.UserQueryResult, error) {
	if isSys, err := IsSystemAdmin(ctx, a.UserModel, a.roleModel); !isSys {
		if err != nil {
			return nil, err
		}
		current, err := a.UserModel.Get(ctx, GetUserID(ctx))
		if err != nil {
			return nil, err
		}
		params.OrgId = current.OrgId
	}

	result, err := a.UserModel.Query(ctx, params, opts...)
	if err != nil {
		return nil, err
	}
	result.Data.FillCreator(result.Data)
	for _, v := range result.Data {
		v.Used, _ = redis.GetRedisClient().Get(ctx, "chart:user:"+v.RecordID).Int()
		v.Unused = v.ChartNum - v.Used
	}

	roles, err := a.roleModel.Query(ctx, schema.RoleQueryParam{})
	if err != nil {
		return nil, err
	}
	result.Data.FillRoleName(roles.Data)

	orgs, err := a.orgModel.Query(ctx, schema.OrganizationQueryParam{})
	if err != nil {
		return nil, err
	}
	result.Data.FillOrgName(orgs.Data)

	return result, nil
}

// Get 查询指定数据
func (a *User) Get(ctx context.Context, recordID string, opts ...schema.UserOptions) (*schema.User, error) {

	item, err := a.UserModel.Get(ctx, recordID, opts...)
	if err != nil {
		return nil, err
	} else if item == nil {
		return nil, errors.ErrNotFound
	}

	// 查询用户菜单
	roleMenu, err := a.roleMenuModel.Query(ctx, schema.RoleMenuQueryParam{RoleId: item.RoleId})
	if err != nil {
		return nil, err
	}
	menus, err := a.menuModel.Query(ctx, schema.MenuQueryParam{RecordIDs: roleMenu.Data.ToMenuIds()})
	if err != nil {
		return nil, err
	}
	item.Menu = menus.Data.ToTrees()

	role, err := a.roleModel.Get(ctx, item.RoleId)
	if err != nil {
		return nil, err
	}
	if role != nil {
		item.RoleCode = role.Code
		item.RoleName = role.Name
	}

	org, err := a.orgModel.Get(ctx, item.OrgId)
	if err != nil {
		return nil, err
	}
	if org != nil {
		item.OrgName = org.Name
	}

	if err := a.loadUserDatasets(ctx, item); err != nil {
		return nil, err
	}

	item.Password = "******"
	item.Used, _ = redis.GetRedisClient().Get(ctx, "chart:user:"+item.RecordID).Int()
	item.Unused = item.ChartNum - item.Used
	return item, nil
}

// GetCurrentUser 查询当前用户
func (a *User) GetCurrentUser(ctx context.Context, recordID string, opts ...schema.UserOptions) (*schema.User, error) {
	if CheckIsRootUser(ctx) {
		return a.getRootInfo(ctx)
	}
	item, err := a.UserModel.Get(ctx, recordID, opts...)
	if err != nil {
		return nil, err
	} else if item == nil {
		return nil, errors.ErrNotFound
	}

	roleMenu, err := a.roleMenuModel.Query(ctx, schema.RoleMenuQueryParam{RoleId: item.RoleId})
	if err != nil {
		return nil, err
	}
	menus, err := a.menuModel.Query(ctx, schema.MenuQueryParam{RecordIDs: roleMenu.Data.ToMenuIds()})
	if err != nil {
		return nil, err
	}
	item.Menu = menus.Data.ToTrees()

	role, err := a.roleModel.Get(ctx, item.RoleId)
	if err != nil {
		return nil, err
	}
	if role != nil {
		item.RoleCode = role.Code
		item.RoleName = role.Name
	}

	org, err := a.orgModel.Get(ctx, item.OrgId)
	if err != nil {
		return nil, err
	}
	if org != nil {
		item.OrgName = org.Name
	}

	if err := a.loadUserDatasets(ctx, item); err != nil {
		return nil, err
	}

	item.Password = "******"
	item.Used, _ = redis.GetRedisClient().Get(ctx, "chart:user:"+item.RecordID).Int()
	item.Unused = item.ChartNum - item.Used
	return item, nil
}

// GetCurrentUserDatasets 获取当前用户有权限的知识库（按组织分组）
func (a *User) GetCurrentUserDatasets(ctx context.Context, opts ...schema.UserOptions) (schema.Organizations, error) {
	rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{BizId: GetUserID(ctx)})
	if err != nil {
		return nil, err
	}
	dataset, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
	if err != nil {
		return nil, err
	}
	orgs, err := a.orgModel.Query(ctx, schema.OrganizationQueryParam{RecordIds: dataset.Data.ToOrgIds()})
	if err != nil {
		return nil, err
	}
	orgs.Data.FillDataset(dataset.Data)
	return orgs.Data, nil
}

func (a *User) getUpdate(ctx context.Context, recordID string) (*schema.User, error) {
	return a.Get(ctx, recordID)
}

// Create 创建数据
// item.Datasets 为分配给该用户的知识库列表（schema.Dataset，仅 RecordID 必填）
// - 类型从知识库本身读取
// - 仅允许分配 共享(1) / 企业(2) 两类；个人(3) 不由创建/编辑用户接口管理
func (a *User) Create(ctx context.Context, item schema.User) error {
	item.RecordID = guid.S()
	item.Status = true
	item.Password = utils.SHA1HashString(strings.ToUpper(item.Password))

	return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
		if err := a.UserModel.Create(ctx, item); err != nil {
			return err
		}
		return a.syncAssignedDatasets(ctx, item.RecordID, item.Datasets)
	})
}

// syncAssignedDatasets 同步“分配给用户”的共享/企业 KB 关系（不影响个人 KB）
func (a *User) syncAssignedDatasets(ctx context.Context, userId string, datasets schema.Datasets) error {
	// 仅清理 type=1/2 的分配，保留 type=3 个人 KB
	if err := a.relationModel.DeleteByBizIdAndType(ctx, userId, schema.DatasetTypePublic); err != nil {
		return err
	}
	if err := a.relationModel.DeleteByBizIdAndType(ctx, userId, schema.DatasetTypeOrg); err != nil {
		return err
	}
	for _, d := range datasets {
		if d.RecordID == "" {
			continue
		}
		ds, err := a.datasetModel.Get(ctx, d.RecordID)
		if err != nil {
			return err
		}
		if ds == nil {
			return errors.New400Response("知识库不存在: " + d.RecordID)
		}
		if ds.Type == schema.DatasetTypePersonal {
			// 个人知识库不通过“分配”流转
			continue
		}
		if err := a.relationModel.Create(ctx, schema.DatasetRelation{
			RecordID:  guid.S(),
			DatasetId: ds.RecordID,
			BizId:     userId,
			Type:      ds.Type,
			CreatorId: GetUserID(ctx),
		}); err != nil {
			return err
		}
	}
	return nil
}

// Update 更新数据
// 知识库权限变化后是否刷新对话助手，改为前端通过独立接口触发确认：
//
//	GET  /web/v1/chat_assistants/permission/check  -> 检查是否一致
//	POST /web/v1/chat_assistants/permission/sync   -> 用户确认后同步
func (a *User) Update(ctx context.Context, recordID string, item schema.User) error {
	oldItem, err := a.UserModel.Get(ctx, recordID)
	if err != nil {
		return err
	} else if oldItem == nil {
		return errors.ErrNotFound
	}
	if item.Password != "" {
		item.Password = utils.SHA1HashString(strings.ToUpper(item.Password))
	}
	return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
		if err := a.syncAssignedDatasets(ctx, recordID, item.Datasets); err != nil {
			return err
		}
		return a.UserModel.Update(ctx, recordID, item)
	})
}

// Delete 删除数据
func (a *User) Delete(ctx context.Context, recordID string) error {
	oldItem, err := a.UserModel.Get(ctx, recordID)
	if err != nil {
		return err
	} else if oldItem == nil {
		return errors.ErrNotFound
	}
	return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
		// 清理该用户的全部授权（含个人KB的映射）
		if err := a.relationModel.DeleteByBizId(ctx, recordID); err != nil {
			return err
		}
		return a.UserModel.Delete(ctx, recordID)
	})
}

// UpdateStatus 更新状态
func (a *User) UpdateStatus(ctx context.Context, recordID string, status bool) error {
	oldItem, err := a.UserModel.Get(ctx, recordID)
	if err != nil {
		return err
	} else if oldItem == nil {
		return errors.ErrNotFound
	}
	return a.UserModel.UpdateStatus(ctx, recordID, status)
}

func (a *User) getRootInfo(ctx context.Context) (*schema.User, error) {
	user := GetRootUser()
	user.Password = "******"
	menu, err := a.menuModel.Query(ctx, schema.MenuQueryParam{})
	if err != nil {
		return nil, err
	}
	user.Menu = menu.Data.ToTrees()
	// root：全部公共/共享知识库 + root 本人的个人知识库
	if err := a.loadAdminDatasets(ctx, user); err != nil {
		return nil, err
	}
	return user, nil
}
