package gateway

import (
	"strings"

	"github.com/tech/sendico/gateway/tron/internal/keymanager"
	"github.com/tech/sendico/gateway/tron/internal/service/gateway/drivers"
	"github.com/tech/sendico/gateway/tron/internal/service/gateway/rpcclient"
	"github.com/tech/sendico/gateway/tron/internal/service/gateway/tronclient"
	"github.com/tech/sendico/gateway/tron/shared"
	clockpkg "github.com/tech/sendico/pkg/clock"
	pmodel "github.com/tech/sendico/pkg/model"
)

// Option configures the Service.
type Option func(*Service)

// WithKeyManager configures the service key manager.
func WithKeyManager(manager keymanager.Manager) Option {
	return func(s *Service) {
		s.keyManager = manager
	}
}

// WithRPCClients configures pre-initialised RPC clients.
func WithRPCClients(clients *rpcclient.Clients) Option {
	return func(s *Service) {
		s.rpcClients = clients
	}
}

// WithTronClients configures native TRON gRPC clients.
func WithTronClients(clients *tronclient.Registry) Option {
	return func(s *Service) {
		s.tronClients = clients
	}
}

// WithNetworks configures supported blockchain networks.
func WithNetworks(networks []shared.Network) Option {
	return func(s *Service) {
		if len(networks) == 0 {
			return
		}
		if s.networks == nil {
			s.networks = make(map[string]shared.Network, len(networks))
		}
		for _, network := range networks {
			if !network.Name.IsValid() {
				continue
			}
			clone := network
			if clone.TokenConfigs == nil {
				clone.TokenConfigs = []shared.TokenContract{}
			}
			for i := range clone.TokenConfigs {
				clone.TokenConfigs[i].Symbol = strings.ToUpper(strings.TrimSpace(clone.TokenConfigs[i].Symbol))
				clone.TokenConfigs[i].ContractAddress = strings.TrimSpace(clone.TokenConfigs[i].ContractAddress)
			}
			clone.Name = network.Name
			s.networks[clone.Name.String()] = clone
		}
	}
}

// WithServiceWallet configures the service wallet binding.
func WithServiceWallet(wallet shared.ServiceWallet) Option {
	return func(s *Service) {
		s.serviceWallet = wallet
	}
}

// WithDriverRegistry configures the chain driver registry.
func WithDriverRegistry(registry *drivers.Registry) Option {
	return func(s *Service) {
		s.drivers = registry
	}
}

// WithClock overrides the service clock.
func WithClock(clk clockpkg.Clock) Option {
	return func(s *Service) {
		if clk != nil {
			s.clock = clk
		}
	}
}

// WithSettings applies gateway settings.
func WithSettings(settings CacheSettings) Option {
	return func(s *Service) {
		s.settings = settings.withDefaults()
	}
}

// WithDiscoveryInvokeURI sets the invoke URI used when announcing the gateway.
func WithDiscoveryInvokeURI(invokeURI string) Option {
	return func(s *Service) {
		s.invokeURI = strings.TrimSpace(invokeURI)
	}
}

// WithMessagingSettings applies messaging driver settings.
func WithMessagingSettings(settings pmodel.SettingsT) Option {
	return func(s *Service) {
		if settings != nil {
			s.msgCfg = settings
		}
	}
}
