package svc

import (
	"backend/internal/config"
	mgo "backend/pkg/library/mongo"
	"backend/pkg/permission/domain/usecase"
	"backend/pkg/permission/repository"
	uc "backend/pkg/permission/usecase"
	"context"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/mon"
	"github.com/zeromicro/go-zero/core/stores/redis"
)

func NewTokenUC(c *config.Config, rds *redis.Redis) usecase.TokenUseCase {
	return uc.MustTokenUseCase(uc.TokenUseCaseParam{
		TokenRepo: repository.MustTokenRepository(repository.TokenRepositoryParam{
			Redis: rds,
		}),
		Config: c,
		Logger: MustLogger(logx.WithContext(context.Background())),
	})
}

type PermissionUC struct {
	PermissionUC   usecase.PermissionUseCase
	RoleUC         usecase.RoleUseCase
	RolePermission usecase.RolePermissionUseCase
	UserRole       usecase.UserRoleUseCase
}

func NewPermissionUC(c *config.Config) PermissionUC {
	// 準備Mongo Config
	conf := &mgo.Conf{
		Schema:                           c.Mongo.Schema,
		Host:                             c.Mongo.Host,
		Database:                         c.Mongo.Database,
		MaxStaleness:                     c.Mongo.MaxStaleness,
		MaxPoolSize:                      c.Mongo.MaxPoolSize,
		MinPoolSize:                      c.Mongo.MinPoolSize,
		MaxConnIdleTime:                  c.Mongo.MaxConnIdleTime,
		Compressors:                      c.Mongo.Compressors,
		EnableStandardReadWriteSplitMode: c.Mongo.EnableStandardReadWriteSplitMode,
		ConnectTimeoutMs:                 c.Mongo.ConnectTimeoutMs,
	}
	if c.Mongo.User != "" {
		conf.User = c.Mongo.User
		conf.Password = c.Mongo.Password
	}

	// 快取選項
	cacheOpts := []cache.Option{
		cache.WithExpiry(c.CacheExpireTime),
		cache.WithNotFoundExpiry(c.CacheWithNotFoundExpiry),
	}
	dbOpts := []mon.Option{
		mgo.SetCustomDecimalType(),
		mgo.InitMongoOptions(*conf),
	}
	permRepo := repository.NewPermissionRepository(repository.PermissionRepositoryParam{
		Conf:      conf,
		CacheConf: c.Cache,
		CacheOpts: cacheOpts,
		DBOpts:    dbOpts,
	})

	rolePermRepo := repository.NewRolePermissionRepository(repository.RolePermissionRepositoryParam{
		Conf:      conf,
		CacheConf: c.Cache,
		CacheOpts: cacheOpts,
		DBOpts:    dbOpts,
	})

	roleRepo := repository.NewRoleRepository(repository.RoleRepositoryParam{
		Conf:      conf,
		CacheConf: c.Cache,
		CacheOpts: cacheOpts,
		DBOpts:    dbOpts,
	})

	userRoleRepo := repository.NewUserRoleRepository(repository.UserRoleRepositoryParam{
		Conf:      conf,
		CacheConf: c.Cache,
		CacheOpts: cacheOpts,
		DBOpts:    dbOpts,
	})

	puc := uc.NewPermissionUseCase(uc.PermissionUseCaseParam{
		RoleRepo:     roleRepo,
		RolePermRepo: rolePermRepo,
		UserRoleRepo: userRoleRepo,
		PermRepo:     permRepo,
	})
	rpuc := uc.NewRolePermissionUseCase(uc.RolePermissionUseCaseParam{
		RoleRepo:     roleRepo,
		RolePermRepo: rolePermRepo,
		UserRoleRepo: userRoleRepo,
		PermRepo:     permRepo,
		PermUseCase:  puc,
		AdminRoleUID: c.RoleConfig.AdminRoleUID,
	})
	ruc := uc.NewRoleUseCase(uc.RoleUseCaseParam{
		RoleRepo:     roleRepo,
		UserRoleRepo: userRoleRepo,
		Config: uc.RoleUseCaseConfig{
			AdminRoleUID: c.RoleConfig.AdminRoleUID,
			UIDPrefix:    c.RoleConfig.UIDPrefix,
			UIDLength:    c.RoleConfig.UIDLength,
		},
		RolePermUseCase: rpuc,
	})

	return PermissionUC{
		PermissionUC:   puc,
		RolePermission: rpuc,
		RoleUC:         ruc,
		UserRole: uc.NewUserRoleUseCase(uc.UserRoleUseCaseParam{
			UserRoleRepo: userRoleRepo,
			RoleRepo:     roleRepo,
		}),
	}
}
