package initialize

import (
	"encoding/json"
	"strconv"
	"strings"
	"time"

	"kra/internal/conf"

	"google.golang.org/protobuf/types/known/durationpb"
)

func compatibleDatabase(value *conf.Data_Database) map[string]any {
	if value == nil {
		return map[string]any{}
	}
	path := value.Host
	if value.Driver == "sqlite" {
		path = value.Path
	}
	return map[string]any{
		"prefix": value.Prefix, "port": value.Port, "config": value.Config,
		"db-name": value.Name, "username": value.User, "password": value.Password,
		"path": path, "engine": value.Engine, "log-mode": value.LogMode,
		"max-idle-conns": value.MaxIdleConns, "max-open-conns": value.MaxOpenConns,
		"conn-max-lifetime": value.ConnMaxLifetime, "singular": value.Singular,
	}
}

func compatibleRedis(value *conf.Data_Redis) map[string]any {
	if value == nil {
		return map[string]any{}
	}
	return map[string]any{"name": value.Name, "addr": value.Addr, "password": value.Password, "db": value.Db, "useCluster": value.UseCluster, "clusterAddrs": value.ClusterAddrs}
}

func compatibleObjectStore(value *conf.AdminBackend_ObjectStore) map[string]any {
	if value == nil {
		return map[string]any{}
	}
	return map[string]any{
		"endpoint": value.Endpoint, "region": value.Region, "bucket": value.Bucket,
		"access-key": value.AccessKey, "secret-key": value.SecretKey, "base-url": value.BaseUrl,
		"path-prefix": value.PathPrefix, "use-ssl": value.UseSsl,
		"s3-force-path-style": value.ForcePathStyle, "account-id": value.AccountId,
	}
}

func compatibleObjectStores(storage *conf.AdminBackend_Storage) map[string]map[string]any {
	if storage == nil {
		storage = &conf.AdminBackend_Storage{}
	}
	aliyun, huawei := storage.AliyunOss, storage.HuaweiObs
	tencent, aws := storage.TencentCos, storage.AwsS3
	cloudflare, minio := storage.CloudflareR2, storage.Minio
	if aliyun == nil {
		aliyun = &conf.AdminBackend_ObjectStore{}
	}
	if huawei == nil {
		huawei = &conf.AdminBackend_ObjectStore{}
	}
	if tencent == nil {
		tencent = &conf.AdminBackend_ObjectStore{}
	}
	if aws == nil {
		aws = &conf.AdminBackend_ObjectStore{}
	}
	if cloudflare == nil {
		cloudflare = &conf.AdminBackend_ObjectStore{}
	}
	if minio == nil {
		minio = &conf.AdminBackend_ObjectStore{}
	}
	return map[string]map[string]any{
		"aliyun-oss":    {"endpoint": aliyun.Endpoint, "access-key-id": aliyun.AccessKey, "access-key-secret": aliyun.SecretKey, "bucket-name": aliyun.Bucket, "bucket-url": aliyun.BaseUrl, "base-path": aliyun.PathPrefix},
		"hua-wei-obs":   {"path": huawei.PathPrefix, "bucket": huawei.Bucket, "endpoint": huawei.Endpoint, "access-key": huawei.AccessKey, "secret-key": huawei.SecretKey},
		"tencent-cos":   {"bucket": tencent.Bucket, "region": tencent.Region, "secret-id": tencent.AccessKey, "secret-key": tencent.SecretKey, "base-url": tencent.BaseUrl, "path-prefix": tencent.PathPrefix},
		"aws-s3":        {"bucket": aws.Bucket, "region": aws.Region, "endpoint": aws.Endpoint, "secret-id": aws.AccessKey, "secret-key": aws.SecretKey, "base-url": aws.BaseUrl, "path-prefix": aws.PathPrefix, "s3-force-path-style": aws.ForcePathStyle, "disable-ssl": !aws.UseSsl},
		"cloudflare-r2": {"bucket": cloudflare.Bucket, "base-url": cloudflare.BaseUrl, "path": cloudflare.PathPrefix, "account-id": cloudflare.AccountId, "access-key-id": cloudflare.AccessKey, "secret-access-key": cloudflare.SecretKey},
		"minio":         {"endpoint": minio.Endpoint, "access-key-id": minio.AccessKey, "access-key-secret": minio.SecretKey, "bucket-name": minio.Bucket, "use-ssl": minio.UseSsl, "base-path": minio.PathPrefix, "bucket-url": minio.BaseUrl},
	}
}

func compatibleConfiguration(data *conf.Data, admin *conf.AdminBackend) map[string]any {
	result := map[string]any{}
	if data == nil {
		data = &conf.Data{}
	}
	if admin == nil {
		admin = &conf.AdminBackend{}
	}
	jwt := admin.Jwt
	if jwt == nil {
		jwt = &conf.AdminBackend_JWT{}
	}
	result["jwt"] = map[string]any{"signing-key": jwt.SigningKey, "expires-time": durationString(jwt.ExpiresTime), "buffer-time": durationString(jwt.BufferTime), "issuer": jwt.Issuer}
	zap := admin.Zap
	if zap == nil {
		zap = &conf.AdminBackend_Zap{}
	}
	result["zap"] = map[string]any{
		"level": zap.Level, "prefix": zap.Prefix, "format": zap.Format, "director": zap.Director,
		"encode-level": zap.EncodeLevel, "stacktrace-key": zap.StacktraceKey, "show-line": zap.ShowLine,
		"log-in-console": zap.LogInConsole, "retention-day": zap.RetentionDay,
		"access-req-body": zap.AccessReqBody, "access-resp-data": zap.AccessRespData,
		"access-req-headers": zap.AccessReqHeaders, "access-log-max-bytes": zap.AccessLogMaxBytes,
		"file-only-modules": zap.FileOnlyModules,
	}
	result["redis"] = compatibleRedis(data.Redis)
	redisList := make([]map[string]any, 0, len(data.RedisList))
	for _, item := range data.RedisList {
		redisList = append(redisList, compatibleRedis(item))
	}
	result["redis-list"] = redisList
	mongo := data.Mongo
	if mongo == nil {
		mongo = &conf.Data_Mongo{}
	}
	hosts := make([]map[string]any, 0, len(mongo.Hosts))
	for _, host := range mongo.Hosts {
		if host != nil {
			hosts = append(hosts, map[string]any{"host": host.Host, "port": host.Port})
		}
	}
	result["mongo"] = map[string]any{"coll": mongo.Coll, "options": mongo.Options, "database": mongo.Database, "username": mongo.Username, "password": mongo.Password, "auth-source": mongo.AuthSource, "min-pool-size": mongo.MinPoolSize, "max-pool-size": mongo.MaxPoolSize, "socket-timeout-ms": mongo.SocketTimeoutMs, "connect-timeout-ms": mongo.ConnectTimeoutMs, "is-zap": mongo.IsZap, "hosts": hosts}
	email := admin.Email
	if email == nil {
		email = &conf.AdminBackend_Email{}
	}
	result["email"] = map[string]any{"to": email.To, "from": email.From, "host": email.Host, "secret": email.Secret, "nickname": email.Nickname, "port": email.Port, "is-ssl": email.IsSsl, "is-loginauth": email.IsLoginAuth}
	system := admin.System
	if system == nil {
		system = &conf.AdminBackend_System{}
	}
	storageType := "local"
	if admin.Storage != nil && admin.Storage.Type != "" {
		storageType = admin.Storage.Type
	}
	driver := ""
	if data.Database != nil {
		driver = data.Database.Driver
	}
	result["system"] = map[string]any{"db-type": driver, "oss-type": storageType, "router-prefix": admin.RouterPrefix, "addr": system.Addr, "iplimit-count": system.IplimitCount, "iplimit-time": system.IplimitTime, "use-multipoint": system.UseMultipoint, "use-redis": system.UseRedis, "use-mongo": system.UseMongo, "use-strict-auth": system.UseStrictAuth, "disable-auto-migrate": system.DisableAutoMigrate}
	for _, name := range []string{"mysql", "mssql", "pgsql", "oracle", "sqlite"} {
		result[name] = map[string]any{}
	}
	if driver != "" {
		result[driver] = compatibleDatabase(data.Database)
	}
	dbList := make([]map[string]any, 0, len(data.DatabaseList))
	for _, item := range data.DatabaseList {
		row := compatibleDatabase(item)
		if item != nil {
			row["type"], row["alias-name"], row["disable"] = item.Driver, item.AliasName, item.Disable
		}
		dbList = append(dbList, row)
	}
	result["db-list"] = dbList
	local := admin.Local
	if local == nil {
		local = &conf.AdminBackend_Local{}
	}
	result["local"] = map[string]any{"path": local.PathPrefix, "store-path": local.StorePath}
	media := admin.Media
	if media == nil {
		media = &conf.AdminBackend_Media{}
	}
	chunkDir := media.ChunkDir
	if chunkDir == "" {
		chunkDir = "uploads/chunks"
	}
	result["media"] = map[string]any{"session-ttl": media.SessionTtl, "max-file-size": media.MaxFileSize, "chunk-dir": chunkDir}
	if admin.Storage == nil {
		admin.Storage = &conf.AdminBackend_Storage{}
	}
	qiniu := admin.Storage.Qiniu
	if qiniu == nil {
		qiniu = &conf.AdminBackend_Qiniu{}
	}
	result["qiniu"] = map[string]any{"zone": qiniu.Zone, "bucket": qiniu.Bucket, "img-path": qiniu.BaseUrl, "access-key": qiniu.AccessKey, "secret-key": qiniu.SecretKey, "use-https": qiniu.UseHttps, "use-cdn-domains": qiniu.UseCdnDomains}
	for key, value := range compatibleObjectStores(admin.Storage) {
		result[key] = value
	}
	disks := make([]map[string]any, 0, len(admin.DiskList))
	for _, disk := range admin.DiskList {
		if disk != nil {
			disks = append(disks, map[string]any{"mount-point": disk.MountPoint})
		}
	}
	result["disk-list"] = disks
	cors := admin.Cors
	if cors == nil {
		cors = &conf.AdminBackend_CORS{}
	}
	whitelist := make([]map[string]any, 0, len(cors.Whitelist))
	for _, rule := range cors.Whitelist {
		if rule != nil {
			whitelist = append(whitelist, map[string]any{"allow-origin": rule.AllowOrigin, "allow-methods": rule.AllowMethods, "allow-headers": rule.AllowHeaders, "expose-headers": rule.ExposeHeaders, "allow-credentials": rule.AllowCredentials})
		}
	}
	result["cors"] = map[string]any{"mode": cors.Mode, "whitelist": whitelist}
	result["app"] = map[string]any{"node": admin.GetApp().GetNode(), "app-id": admin.GetApp().GetAppId(), "env": admin.GetApp().GetEnv()}
	return result
}

func objectMap(value any) map[string]any {
	result, _ := value.(map[string]any)
	return result
}

func stringValue(values map[string]any, key string) string {
	value, _ := values[key].(string)
	return value
}

func boolValue(values map[string]any, key string, fallback bool) bool {
	value, ok := values[key].(bool)
	if !ok {
		return fallback
	}
	return value
}

func int64Value(values map[string]any, key string, fallback int64) int64 {
	value, ok := values[key].(float64)
	if !ok {
		return fallback
	}
	return int64(value)
}

func stringSliceValue(values map[string]any, key string, fallback []string) []string {
	items, ok := values[key].([]any)
	if !ok {
		return fallback
	}
	result := make([]string, 0, len(items))
	for _, item := range items {
		if value, ok := item.(string); ok {
			result = append(result, value)
		}
	}
	return result
}

func applyCompatibleRedis(target *conf.Data_Redis, values map[string]any) {
	if target == nil || values == nil {
		return
	}
	target.Name, target.Addr = stringValue(values, "name"), stringValue(values, "addr")
	if password := stringValue(values, "password"); password != "" && password != "******" {
		target.Password = password
	}
	target.Db = int32(int64Value(values, "db", int64(target.Db)))
	target.UseCluster = boolValue(values, "useCluster", target.UseCluster)
	target.ClusterAddrs = stringSliceValue(values, "clusterAddrs", target.ClusterAddrs)
}

func durationValue(raw string, fallback *durationpb.Duration) *durationpb.Duration {
	if raw == "" {
		return fallback
	}
	value, err := parseCompatibleDuration(raw)
	if err != nil {
		return fallback
	}
	return durationpb.New(value)
}

func parseCompatibleDuration(raw string) (time.Duration, error) {
	raw = strings.TrimSpace(raw)
	if value, err := time.ParseDuration(raw); err == nil {
		return value, nil
	}
	if index := strings.Index(raw, "d"); index >= 0 {
		days, _ := strconv.Atoi(raw[:index])
		value := time.Duration(days) * 24 * time.Hour
		remainder, err := time.ParseDuration(raw[index+1:])
		if err != nil {
			return value, nil
		}
		return value + remainder, nil
	}
	nanoseconds, err := strconv.ParseInt(raw, 10, 64)
	return time.Duration(nanoseconds), err
}

func applyCompatibleDatabase(target *conf.Data_Database, values map[string]any, driver string) {
	if target == nil || values == nil {
		return
	}
	target.Driver = driver
	target.Prefix, target.Port, target.Config = stringValue(values, "prefix"), stringValue(values, "port"), stringValue(values, "config")
	target.Name, target.User = stringValue(values, "db-name"), stringValue(values, "username")
	if password := stringValue(values, "password"); password != "" && password != "******" {
		target.Password = password
	}
	if driver == "sqlite" {
		target.Path = stringValue(values, "path")
	} else {
		target.Host = stringValue(values, "path")
	}
	target.Engine, target.LogMode = stringValue(values, "engine"), stringValue(values, "log-mode")
	target.MaxIdleConns = int32(int64Value(values, "max-idle-conns", int64(target.MaxIdleConns)))
	target.MaxOpenConns = int32(int64Value(values, "max-open-conns", int64(target.MaxOpenConns)))
	target.ConnMaxLifetime = int32(int64Value(values, "conn-max-lifetime", int64(target.ConnMaxLifetime)))
	target.Singular = boolValue(values, "singular", target.Singular)
}

func applyCompatibleObjectStore(target *conf.AdminBackend_ObjectStore, values map[string]any) {
	if target == nil || values == nil {
		return
	}
	target.Endpoint, target.Region, target.Bucket = stringValue(values, "endpoint"), stringValue(values, "region"), stringValue(values, "bucket")
	if target.Bucket == "" {
		target.Bucket = stringValue(values, "bucket-name")
	}
	target.AccessKey = stringValue(values, "access-key")
	if target.AccessKey == "" {
		target.AccessKey = stringValue(values, "access-key-id")
	}
	if target.AccessKey == "" {
		target.AccessKey = stringValue(values, "secret-id")
	}
	secret := stringValue(values, "secret-key")
	if secret == "" {
		secret = stringValue(values, "access-key-secret")
	}
	if secret == "" {
		secret = stringValue(values, "secret-access-key")
	}
	if secret != "" && secret != "******" {
		target.SecretKey = secret
	}
	target.BaseUrl = stringValue(values, "base-url")
	if target.BaseUrl == "" {
		target.BaseUrl = stringValue(values, "bucket-url")
	}
	target.PathPrefix = stringValue(values, "path-prefix")
	if target.PathPrefix == "" {
		target.PathPrefix = stringValue(values, "base-path")
	}
	if target.PathPrefix == "" {
		target.PathPrefix = stringValue(values, "path")
	}
	target.UseSsl = boolValue(values, "use-ssl", !boolValue(values, "disable-ssl", !target.UseSsl))
	target.ForcePathStyle = boolValue(values, "s3-force-path-style", target.ForcePathStyle)
	target.AccountId = stringValue(values, "account-id")
}

func applyCompatibleConfiguration(raw json.RawMessage, data *conf.Data, admin *conf.AdminBackend) error {
	var values map[string]any
	if err := json.Unmarshal(raw, &values); err != nil {
		return err
	}
	if _, compatibleShape := values["system"]; !compatibleShape {
		return nil
	}
	if data.Database == nil {
		data.Database = &conf.Data_Database{}
	}
	if admin.System == nil {
		admin.System = &conf.AdminBackend_System{}
	}
	if admin.Storage == nil {
		admin.Storage = &conf.AdminBackend_Storage{}
	}
	system := objectMap(values["system"])
	driver := stringValue(system, "db-type")
	if driver == "" {
		driver = data.Database.Driver
	}
	applyCompatibleDatabase(data.Database, objectMap(values[driver]), driver)
	admin.Storage.Type = stringValue(system, "oss-type")
	admin.RouterPrefix = stringValue(system, "router-prefix")
	admin.System.UseMultipoint = boolValue(system, "use-multipoint", admin.System.UseMultipoint)
	admin.System.UseRedis = boolValue(system, "use-redis", admin.System.UseRedis)
	admin.System.UseMongo = boolValue(system, "use-mongo", admin.System.UseMongo)
	admin.System.UseStrictAuth = boolValue(system, "use-strict-auth", admin.System.UseStrictAuth)
	admin.System.DisableAutoMigrate = boolValue(system, "disable-auto-migrate", admin.System.DisableAutoMigrate)
	admin.System.Addr = int32(int64Value(system, "addr", int64(admin.System.Addr)))
	admin.System.IplimitCount = int32(int64Value(system, "iplimit-count", int64(admin.System.IplimitCount)))
	admin.System.IplimitTime = int32(int64Value(system, "iplimit-time", int64(admin.System.IplimitTime)))
	if admin.Jwt == nil {
		admin.Jwt = &conf.AdminBackend_JWT{}
	}
	jwt := objectMap(values["jwt"])
	if secret := stringValue(jwt, "signing-key"); secret != "" && secret != "******" {
		admin.Jwt.SigningKey = secret
	}
	admin.Jwt.ExpiresTime = durationValue(stringValue(jwt, "expires-time"), admin.Jwt.ExpiresTime)
	admin.Jwt.BufferTime = durationValue(stringValue(jwt, "buffer-time"), admin.Jwt.BufferTime)
	admin.Jwt.Issuer = stringValue(jwt, "issuer")
	if admin.Zap == nil {
		admin.Zap = &conf.AdminBackend_Zap{}
	}
	zap := objectMap(values["zap"])
	admin.Zap.Level, admin.Zap.Prefix, admin.Zap.Format, admin.Zap.Director = stringValue(zap, "level"), stringValue(zap, "prefix"), stringValue(zap, "format"), stringValue(zap, "director")
	admin.Zap.EncodeLevel, admin.Zap.StacktraceKey = stringValue(zap, "encode-level"), stringValue(zap, "stacktrace-key")
	admin.Zap.ShowLine, admin.Zap.LogInConsole = boolValue(zap, "show-line", admin.Zap.ShowLine), boolValue(zap, "log-in-console", admin.Zap.LogInConsole)
	admin.Zap.RetentionDay = int32(int64Value(zap, "retention-day", int64(admin.Zap.RetentionDay)))
	admin.Zap.AccessReqBody = boolValue(zap, "access-req-body", admin.Zap.AccessReqBody)
	admin.Zap.AccessRespData = boolValue(zap, "access-resp-data", admin.Zap.AccessRespData)
	admin.Zap.AccessReqHeaders = boolValue(zap, "access-req-headers", admin.Zap.AccessReqHeaders)
	admin.Zap.AccessLogMaxBytes = int32(int64Value(zap, "access-log-max-bytes", int64(admin.Zap.AccessLogMaxBytes)))
	if list, ok := zap["file-only-modules"].([]any); ok {
		admin.Zap.FileOnlyModules = admin.Zap.FileOnlyModules[:0]
		for _, item := range list {
			if value, ok := item.(string); ok {
				admin.Zap.FileOnlyModules = append(admin.Zap.FileOnlyModules, value)
			}
		}
	}
	if data.Redis == nil {
		data.Redis = &conf.Data_Redis{}
	}
	applyCompatibleRedis(data.Redis, objectMap(values["redis"]))
	if items, ok := values["redis-list"].([]any); ok {
		current := make(map[string]*conf.Data_Redis, len(data.RedisList))
		for _, item := range data.RedisList {
			if item != nil {
				current[item.Name] = item
			}
		}
		data.RedisList = make([]*conf.Data_Redis, 0, len(items))
		for _, item := range items {
			values := objectMap(item)
			target := current[stringValue(values, "name")]
			if target == nil {
				target = &conf.Data_Redis{}
			}
			applyCompatibleRedis(target, values)
			data.RedisList = append(data.RedisList, target)
		}
	}
	if mongo := objectMap(values["mongo"]); mongo != nil {
		if data.Mongo == nil {
			data.Mongo = &conf.Data_Mongo{}
		}
		data.Mongo.Coll, data.Mongo.Options, data.Mongo.Database = stringValue(mongo, "coll"), stringValue(mongo, "options"), stringValue(mongo, "database")
		data.Mongo.Username, data.Mongo.AuthSource = stringValue(mongo, "username"), stringValue(mongo, "auth-source")
		if password := stringValue(mongo, "password"); password != "" && password != "******" {
			data.Mongo.Password = password
		}
		data.Mongo.MinPoolSize = uint64(int64Value(mongo, "min-pool-size", int64(data.Mongo.MinPoolSize)))
		data.Mongo.MaxPoolSize = uint64(int64Value(mongo, "max-pool-size", int64(data.Mongo.MaxPoolSize)))
		data.Mongo.SocketTimeoutMs = int64Value(mongo, "socket-timeout-ms", data.Mongo.SocketTimeoutMs)
		data.Mongo.ConnectTimeoutMs = int64Value(mongo, "connect-timeout-ms", data.Mongo.ConnectTimeoutMs)
		data.Mongo.IsZap = boolValue(mongo, "is-zap", data.Mongo.IsZap)
		if hosts, ok := mongo["hosts"].([]any); ok {
			data.Mongo.Hosts = make([]*conf.Data_MongoHost, 0, len(hosts))
			for _, item := range hosts {
				host := objectMap(item)
				data.Mongo.Hosts = append(data.Mongo.Hosts, &conf.Data_MongoHost{Host: stringValue(host, "host"), Port: stringValue(host, "port")})
			}
		}
	}
	if items, ok := values["db-list"].([]any); ok {
		current := make(map[string]*conf.Data_Database, len(data.DatabaseList))
		for _, item := range data.DatabaseList {
			if item != nil {
				current[item.AliasName] = item
			}
		}
		data.DatabaseList = make([]*conf.Data_Database, 0, len(items))
		for _, item := range items {
			row := objectMap(item)
			alias := stringValue(row, "alias-name")
			target := current[alias]
			if target == nil {
				target = &conf.Data_Database{}
			}
			applyCompatibleDatabase(target, row, stringValue(row, "type"))
			target.AliasName, target.Disable = alias, boolValue(row, "disable", target.Disable)
			data.DatabaseList = append(data.DatabaseList, target)
		}
	}
	if admin.Email == nil {
		admin.Email = &conf.AdminBackend_Email{}
	}
	email := objectMap(values["email"])
	admin.Email.To, admin.Email.From, admin.Email.Host = stringValue(email, "to"), stringValue(email, "from"), stringValue(email, "host")
	admin.Email.Nickname = stringValue(email, "nickname")
	admin.Email.Port = int32(int64Value(email, "port", int64(admin.Email.Port)))
	admin.Email.IsSsl, admin.Email.IsLoginAuth = boolValue(email, "is-ssl", admin.Email.IsSsl), boolValue(email, "is-loginauth", admin.Email.IsLoginAuth)
	if secret := stringValue(email, "secret"); secret != "" && secret != "******" {
		admin.Email.Secret = secret
	}
	if admin.Local == nil {
		admin.Local = &conf.AdminBackend_Local{}
	}
	local := objectMap(values["local"])
	admin.Local.PathPrefix, admin.Local.StorePath = stringValue(local, "path"), stringValue(local, "store-path")
	if admin.Media == nil {
		admin.Media = &conf.AdminBackend_Media{}
	}
	media := objectMap(values["media"])
	admin.Media.SessionTtl = int32(int64Value(media, "session-ttl", int64(admin.Media.SessionTtl)))
	admin.Media.MaxFileSize = int64Value(media, "max-file-size", admin.Media.MaxFileSize)
	admin.Media.ChunkDir = stringValue(media, "chunk-dir")
	if admin.Storage.Qiniu == nil {
		admin.Storage.Qiniu = &conf.AdminBackend_Qiniu{}
	}
	qiniu := objectMap(values["qiniu"])
	admin.Storage.Qiniu.Zone, admin.Storage.Qiniu.Bucket, admin.Storage.Qiniu.BaseUrl = stringValue(qiniu, "zone"), stringValue(qiniu, "bucket"), stringValue(qiniu, "img-path")
	admin.Storage.Qiniu.AccessKey = stringValue(qiniu, "access-key")
	if secret := stringValue(qiniu, "secret-key"); secret != "" && secret != "******" {
		admin.Storage.Qiniu.SecretKey = secret
	}
	admin.Storage.Qiniu.UseHttps, admin.Storage.Qiniu.UseCdnDomains = boolValue(qiniu, "use-https", admin.Storage.Qiniu.UseHttps), boolValue(qiniu, "use-cdn-domains", admin.Storage.Qiniu.UseCdnDomains)
	stores := []struct {
		key    string
		target **conf.AdminBackend_ObjectStore
	}{{"aliyun-oss", &admin.Storage.AliyunOss}, {"hua-wei-obs", &admin.Storage.HuaweiObs}, {"tencent-cos", &admin.Storage.TencentCos}, {"aws-s3", &admin.Storage.AwsS3}, {"cloudflare-r2", &admin.Storage.CloudflareR2}, {"minio", &admin.Storage.Minio}}
	for _, store := range stores {
		if *store.target == nil {
			*store.target = &conf.AdminBackend_ObjectStore{}
		}
		applyCompatibleObjectStore(*store.target, objectMap(values[store.key]))
	}
	if disks, ok := values["disk-list"].([]any); ok {
		admin.DiskList = make([]*conf.AdminBackend_Disk, 0, len(disks))
		for _, item := range disks {
			disk := objectMap(item)
			admin.DiskList = append(admin.DiskList, &conf.AdminBackend_Disk{MountPoint: stringValue(disk, "mount-point")})
		}
	}
	if cors := objectMap(values["cors"]); cors != nil {
		if admin.Cors == nil {
			admin.Cors = &conf.AdminBackend_CORS{}
		}
		admin.Cors.Mode = stringValue(cors, "mode")
		if rules, ok := cors["whitelist"].([]any); ok {
			admin.Cors.Whitelist = make([]*conf.AdminBackend_CORSRule, 0, len(rules))
			for _, item := range rules {
				rule := objectMap(item)
				admin.Cors.Whitelist = append(admin.Cors.Whitelist, &conf.AdminBackend_CORSRule{AllowOrigin: stringValue(rule, "allow-origin"), AllowMethods: stringValue(rule, "allow-methods"), AllowHeaders: stringValue(rule, "allow-headers"), ExposeHeaders: stringValue(rule, "expose-headers"), AllowCredentials: boolValue(rule, "allow-credentials", false)})
			}
		}
	}
	if app := objectMap(values["app"]); app != nil {
		if admin.App == nil {
			admin.App = &conf.AdminBackend_App{}
		}
		admin.App.Node, admin.App.AppId, admin.App.Env = stringValue(app, "node"), stringValue(app, "app-id"), stringValue(app, "env")
	}
	return nil
}
