package internal

import (
	"context"
	"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"
)

// NewOrganization 创建Organization
func NewOrganization(
	mTrans model.ITrans,
	mOrganization model.IOrganization,
	mFile model.IDatasetFile,
	mDataset model.IDataset,
	mUser model.IUser,
	mRole model.IRole,
	mRelation model.IDatasetRelation,
) *Organization {
	return &Organization{
		transModel:        mTrans,
		organizationModel: mOrganization,
		fileModel:         mFile,
		datasetModel:      mDataset,
		userModel:         mUser,
		roleModel:         mRole,
		relationModel:     mRelation,
	}
}

// Organization 创建Organization对象
type Organization struct {
	organizationModel model.IOrganization
	transModel        model.ITrans
	fileModel         model.IDatasetFile
	datasetModel      model.IDataset
	userModel         model.IUser
	roleModel         model.IRole
	relationModel     model.IDatasetRelation
}

// Query 查询数据
func (a *Organization) Query(ctx context.Context, params schema.OrganizationQueryParam, opts ...schema.OrganizationQueryOptions) (*schema.OrganizationQueryResult, error) {

	dataset, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{})
	if err != nil {
		return nil, err
	}
	// 非系统管理员仅可看到本组织
	if isSys, _ := IsSystemAdmin(ctx, a.userModel, a.roleModel); !isSys {
		user, err := a.userModel.Get(ctx, GetUserID(ctx))
		if err != nil {
			return nil, err
		}
		// 基于组织+用户维度的授权查询本组织可访问的知识库
		bizIds := []string{user.OrgId, GetUserID(ctx)}
		rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{BizIds: bizIds})
		if err != nil {
			return nil, err
		}
		dataset, err = a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
		if err != nil {
			return nil, err
		}
		if len(dataset.Data) == 0 {
			params.RecordIds = []string{user.OrgId}
		} else {
			params.RecordIds = dataset.Data.ToOrgIds()
			if params.RecordIds == nil {
				params.RecordIds = []string{}
			}
			params.RecordIds = append(params.RecordIds, user.OrgId)
		}
	}

	result, err := a.organizationModel.Query(ctx, params, opts...)
	if err != nil {
		return nil, err
	}
	if len(result.Data) > 0 {
		user, err := a.userModel.Query(ctx, schema.UserQueryParam{RecordIDs: result.Data.ToUserIds()})
		if err != nil {
			return nil, err
		}
		dataset.Data.FillCreator(user.Data)
		result.Data.FillCreator(user.Data)
		result.Data.FillDataset(dataset.Data)
	}

	for _, v := range result.Data {
		v.Used, _ = redis.GetRedisClient().Get(ctx, "chart:organization:"+v.RecordID).Int()
		v.Unused = v.ChartNum - v.Used
	}

	return result, nil
}

// Get 查询指定数据
func (a *Organization) Get(ctx context.Context, recordID string, opts ...schema.OrganizationQueryOptions) (*schema.Organization, error) {
	item, err := a.organizationModel.Get(ctx, recordID, opts...)
	if err != nil {
		return nil, err
	} else if item == nil {
		return nil, errors.ErrNotFound
	}
	user, err := a.userModel.Get(ctx, item.CreatorId)
	if err != nil {
		return nil, err
	}
	if user != nil {
		item.CreatorName = user.RealName
	}

	// 查询组织维度有权限的知识库（包含自建企业KB 与 被分配的共享KB）
	rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{BizId: recordID})
	if err != nil {
		return nil, err
	}
	if len(rel.Data) > 0 {
		datasets, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
		if err != nil {
			return nil, err
		}
		item.Datasets = datasets.Data
	}

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

// Create 创建数据（仅系统管理员）：item.Datasets 为勾选共享给该组织的知识库列表（填 record_id）
func (a *Organization) Create(ctx context.Context, item schema.Organization) error {
	ok, err := IsSystemAdmin(ctx, a.userModel, a.roleModel)
	if err != nil {
		return err
	}
	if !ok {
		return errors.New400Response("仅系统管理员可创建组织")
	}
	item.RecordID = guid.S()
	item.CreatorId = GetUserID(ctx)

	org, err := a.organizationModel.GetByName(ctx, item.Name)
	if err != nil {
		return err
	} else if org != nil {
		return errors.New("命名重复")
	}

	return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
		if err := a.organizationModel.Create(ctx, item); err != nil {
			return err
		}
		// 将勾选的共享知识库分配给该组织，写入关系映射
		for _, d := range item.Datasets {
			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.DatasetTypePublic {
				return errors.New400Response("仅共享知识库可分配给组织: " + d.RecordID)
			}
			if err := a.relationModel.Create(ctx, schema.DatasetRelation{
				RecordID:  guid.S(),
				DatasetId: ds.RecordID,
				BizId:     item.RecordID,
				Type:      schema.DatasetTypePublic,
				CreatorId: GetUserID(ctx),
			}); err != nil {
				return err
			}
		}
		return nil
	})
}

// Update 更新数据
// 组织的共享知识库（type=1）发生变化时，同步刷新该组织所有企业管理员的共享知识库权限
func (a *Organization) Update(ctx context.Context, recordID string, item schema.Organization) error {
	oldItem, err := a.organizationModel.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 {
		// 仅重置组织级的共享知识库映射（type=1），保留该组织企业自建KB（type=2）
		if err := a.relationModel.DeleteByBizIdAndType(ctx, recordID, schema.DatasetTypePublic); err != nil {
			return err
		}
		// 收集本次分配给组织的共享知识库
		sharedDatasetIds := make([]string, 0, len(item.Datasets))
		for _, d := range item.Datasets {
			ds, err := a.datasetModel.Get(ctx, d.RecordID)
			if err != nil {
				return err
			}
			if ds == nil || ds.Type != schema.DatasetTypePublic {
				return errors.New400Response("仅共享知识库可分配给组织: " + d.RecordID)
			}
			if err := a.relationModel.Create(ctx, schema.DatasetRelation{
				RecordID:  guid.S(),
				DatasetId: d.RecordID,
				BizId:     recordID,
				Type:      schema.DatasetTypePublic,
				CreatorId: GetUserID(ctx),
			}); err != nil {
				return err
			}
			sharedDatasetIds = append(sharedDatasetIds, d.RecordID)
		}

		// 同步刷新该组织所有企业管理员的用户级共享知识库映射
		admins, err := a.userModel.Query(ctx, schema.UserQueryParam{
			OrgId:    recordID,
			RoleCode: []string{RoleCodeEnterpriseAdmin},
		})
		if err != nil {
			return err
		}
		for _, admin := range admins.Data {
			if err := a.relationModel.DeleteByBizIdAndType(ctx, admin.RecordID, schema.DatasetTypePublic); err != nil {
				return err
			}
			for _, dsId := range sharedDatasetIds {
				if err := a.relationModel.Create(ctx, schema.DatasetRelation{
					RecordID:  guid.S(),
					DatasetId: dsId,
					BizId:     admin.RecordID,
					Type:      schema.DatasetTypePublic,
					CreatorId: GetUserID(ctx),
				}); err != nil {
					return err
				}
			}
		}
		return a.organizationModel.Update(ctx, recordID, item)
	})
}

// Delete 删除数据
func (a *Organization) Delete(ctx context.Context, recordID string) error {
	return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
		oldItem, err := a.organizationModel.Get(ctx, recordID)
		if err != nil {
			return err
		} else if oldItem == nil {
			return errors.ErrNotFound
		}

		// 先清理组织级映射
		if err := a.relationModel.DeleteByBizId(ctx, recordID); err != nil {
			return err
		}

		// 删除组织自建的企业知识库及其文件/关系
		dataset, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{OrgId: recordID, Type: schema.DatasetTypeOrg})
		if err != nil {
			return err
		}
		if len(dataset.Data) > 0 {
			ids := dataset.Data.ToRecordIds()
			for _, id := range ids {
				if err := a.relationModel.DeleteByDatasetId(ctx, id); err != nil {
					return err
				}
			}
			if err := a.fileModel.DeleteByDatasetIds(ctx, ids); err != nil {
				return err
			}
			if err := a.datasetModel.DeleteByOrgId(ctx, recordID); err != nil {
				return err
			}
		}
		return a.organizationModel.Delete(ctx, recordID)
	})
}

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