package base

import (
	"context"

	"github.com/tidbcloud/dataflow-service/app/repo/entity"
	"github.com/tidbcloud/dataflow-service/internal/db/dbutil"
	"github.com/tidbcloud/dataflow-service/pkg/account/accountdb"
	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

type Model interface {
	// BaseUserContext returns base user context
	BaseUserContext(ctx context.Context, user *accountdb.User, moduleName string) UserContext
	// Log returns model logger
	Log() *zap.Logger
}

var _ Model = &model{}

type model struct {
	log *zap.Logger
}

func NewModel(log *zap.Logger) Model {
	return &model{log: log}
}

func (m model) BaseUserContext(ctx context.Context, user *accountdb.User, moduleName string) UserContext {
	logger := m.log.With(
		zap.Uint64("tenantID", user.TenantID),
		zap.Uint64("userID", user.ID),
		zap.String("module", moduleName)).
		With(log.FieldsFromContext(ctx)...)
	return newUserContext(user, logger)
}

func (m model) Log() *zap.Logger {
	return m.log
}

type UserContext interface {
	// CheckProjectPermission checks whether user has permission to the project
	CheckProjectPermission(projectID entity.ID) error
	// UserID returns current user id
	UserID() entity.ID
	// Log returns a context logger
	Log() *zap.Logger
}

var _ UserContext = &userContext{}

type userContext struct {
	user *accountdb.User
	log  *zap.Logger
}

func newUserContext(user *accountdb.User, log *zap.Logger) *userContext {
	return &userContext{user: user, log: log}
}

func (u userContext) UserID() entity.ID {
	return entity.ID(u.user.ID)
}

func (u userContext) Log() *zap.Logger {
	return u.log
}

func (u userContext) CheckProjectPermission(projectID entity.ID) error {
	return dbutil.CheckProjectID(u.user.Projects, projectID)
}


