package main

import (
	"fmt"
	"sync"
)

type Module interface {
	Name() string
	Check(pk string, cfg *Config) (*ModuleResult, error)
	Enabled(cfg *Config) bool
}

type ModuleResult struct {
	Address string
	Balance float64
	Details string
	Tokens  int
}

type ModuleManager struct {
	modules []Module
	cfg     *Config
}

func NewModuleManager(cfg *Config) *ModuleManager {
	mm := &ModuleManager{
		cfg:     cfg,
		modules: []Module{},
	}

	if cfg.EnableAxiomModule {
		mm.modules = append(mm.modules, &AxiomModule{})
	}

	if cfg.EnableEVMModule {
		mm.modules = append(mm.modules, &EVMModule{})
	}

	return mm
}

func (mm *ModuleManager) GetEnabledModules() []Module {
	return mm.modules
}

func (mm *ModuleManager) CheckAll(pk string) (float64, string) {
	if len(mm.modules) == 0 {
		return 0, ""
	}

	var wg sync.WaitGroup
	resultsChan := make(chan *ModuleResult, len(mm.modules))

	for _, module := range mm.modules {
		wg.Add(1)
		go func(m Module) {
			defer wg.Done()
			result, err := m.Check(pk, mm.cfg)
			if err == nil && result != nil {
				resultsChan <- result
			}
		}(module)
	}

	wg.Wait()
	close(resultsChan)

	var totalBalance float64
	var details string

	for result := range resultsChan {
		totalBalance += result.Balance
		details += result.Details
	}

	return totalBalance, details
}

type AxiomModule struct{}

func (m *AxiomModule) Name() string {
	return "Axiom"
}

func (m *AxiomModule) Enabled(cfg *Config) bool {
	return cfg.EnableAxiomModule
}

func (m *AxiomModule) Check(pk string, cfg *Config) (*ModuleResult, error) {
	address, balance, err := getAxiomBalance(pk)
	if err != nil {
		return nil, nil
	}

	return &ModuleResult{
		Address: address,
		Balance: balance,
		Details: fmt.Sprintf("  [Axiom] %s - $%.2f\n", address, balance),
	}, nil
}

type EVMModule struct{}

func (m *EVMModule) Name() string {
	return "EVM (DeBank)"
}

func (m *EVMModule) Enabled(cfg *Config) bool {
	return cfg.EnableEVMModule
}

func (m *EVMModule) Check(pk string, cfg *Config) (*ModuleResult, error) {
	ax, err := getAxiomWallet(pk)
	if err != nil {
		return nil, nil
	}

	if ax.Evm == "" {
		return nil, nil
	}

	balance, details, err := getDeBankBalance(ax.Evm)
	if err != nil {
		return nil, nil
	}

	if balance == 0 {
		return nil, nil
	}

	result := &ModuleResult{
		Address: ax.Evm,
		Balance: balance,
		Details: fmt.Sprintf("  [EVM] %s - $%.2f\n", ax.Evm, balance),
	}

	if details != "" {
		result.Details += details
	}

	return result, nil
}
