package dao

import (
	"sync"

	"github.com/tidbcloud/account/internel/dao/resref"

	"github.com/tidbcloud/account/internel/dao/flag"

	"github.com/golang/mock/gomock"
	"github.com/tidbcloud/account/internel/dao/apikey"
	"github.com/tidbcloud/account/internel/dao/authcenter"
	"github.com/tidbcloud/account/internel/dao/cross"
	"github.com/tidbcloud/account/internel/dao/dbuser"
	"github.com/tidbcloud/account/internel/dao/domain"
	"github.com/tidbcloud/account/internel/dao/history"
	"github.com/tidbcloud/account/internel/dao/message"
	"github.com/tidbcloud/account/internel/dao/msp"
	"github.com/tidbcloud/account/internel/dao/org"
	"github.com/tidbcloud/account/internel/dao/project"
	"github.com/tidbcloud/account/internel/dao/rbac"
	"github.com/tidbcloud/account/internel/dao/role"
	"github.com/tidbcloud/account/internel/dao/scim"
	"github.com/tidbcloud/account/internel/dao/sso"
	"github.com/tidbcloud/account/internel/dao/survey"
	"github.com/tidbcloud/account/internel/dao/user"
)

type DaoMockHub struct {
	Cross   *cross.MockCrossDaoIface
	User    *user.MockUserDaoIface
	Org     *org.MockOrgDaoIface
	Project *project.MockProjectDaoIface
	Role    *role.MockRoleDaoIface
	Rbac    *rbac.MockRbacDaoIface
	Message *message.MockMessageDaoIface
}

func NewDaoMockHub(ctrl *gomock.Controller) *DaoMockHub {
	h := &DaoMockHub{
		Cross:   cross.NewMockCrossDaoIface(ctrl),
		User:    user.NewMockUserDaoIface(ctrl),
		Org:     org.NewMockOrgDaoIface(ctrl),
		Project: project.NewMockProjectDaoIface(ctrl),
		Role:    role.NewMockRoleDaoIface(ctrl),
		Rbac:    rbac.NewMockRbacDaoIface(ctrl),
		Message: message.NewMockMessageDaoIface(ctrl),
	}

	return h
}

func (d *DaoMockHub) NewHub() *DaoHub {
	h := &DaoHub{
		Mock:    d,
		Cross:   d.Cross,
		User:    d.User,
		Org:     d.Org,
		Project: d.Project,
		Role:    d.Role,
		Rbac:    d.Rbac,
		Message: d.Message,
	}

	return h
}

type DaoHub struct {
	Mock             *DaoMockHub
	Cross            cross.CrossDaoIface
	User             user.UserDaoIface
	History          history.HistoryDaoIface
	Org              org.OrgDaoIface
	Project          project.ProjectDaoIface
	Role             role.RoleDaoIface
	Rbac             rbac.RbacDaoIface
	Message          message.MessageDaoIface
	DBUser           dbuser.DBUserDaoIface
	ApiKey           apikey.ApiKeyDaoIface
	OrgAuthMethod    sso.OrgAuthMethodDaoIface
	ScimGroup        scim.ScimGroupDaoIface
	OrgDomain        domain.OrgDomainDaoIface
	Msp              msp.MspDaoIface
	ClusterUser      authcenter.ClusterUserDaoIface
	Survey           survey.SurveyDaoIface
	FeatureFlag      flag.FeatureFlagDaoIface
	ResourceRelation resref.ResourceRelationDaoIface
	UserSession      user.UserSessionDaoIface
}

func NewDaoHub() *DaoHub {
	d := &DaoHub{
		Cross:            cross.NewDao(),
		User:             user.NewDao(),
		History:          history.NewDao(),
		Org:              org.NewDao(),
		Project:          project.NewDao(),
		Role:             role.NewDao(),
		Rbac:             rbac.NewRbacDao(),
		Message:          message.NewDao(),
		DBUser:           dbuser.NewDBUserDao(),
		ApiKey:           apikey.NewApiKeyDao(),
		OrgAuthMethod:    sso.NewOrgAuthMethodDao(),
		ScimGroup:        scim.NewScimGroupDao(),
		Msp:              msp.NewMspDao(),
		ClusterUser:      authcenter.NewClusterUserDao(),
		Survey:           survey.NewSurveyDao(),
		FeatureFlag:      flag.NewFeatureFlagDao(),
		ResourceRelation: resref.NewResourceRelationDao(),
		UserSession:      user.NewUserSessionDao(),
		OrgDomain:        domain.NewOrgDomainDao(),
	}

	return d
}

var (
	daoHubInitOnce sync.Once
	daoHub         *DaoHub
)

func GetDaoHub() *DaoHub {
	daoHubInitOnce.Do(func() {
		daoHub = NewDaoHub()
	})
	return daoHub
}

func NewMockHub(ctrl *gomock.Controller) *DaoHub {
	m := NewDaoMockHub(ctrl)
	return m.NewHub()
}
