package currency

import (
	"context"
	"fmt"
	"time"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
)

type Service struct {
	repo         repository.CurrencyRepository
	baseCurrency domain.IntCurrency
	fixerFetcher *FixerFetcher
}

func NewService(repo repository.CurrencyRepository, baseCurrency domain.IntCurrency, fixerFetcher *FixerFetcher) *Service {
	return &Service{repo: repo}
}

func (s *Service) Convert(ctx context.Context, amount float64, from, to domain.IntCurrency) (float64, error) {
	if from == to {
		return amount, nil
	}

	rate, err := s.repo.GetExchangeRate(ctx, from, to)
	if err != nil {
		return 0, err
	}

	return rate.Convert(amount)
}

func (s *Service) GetSupportedCurrencies(ctx context.Context) ([]domain.IntCurrency, error) {
	return s.repo.GetSupportedCurrencies(ctx)
}

func (s *Service) UpdateRates(ctx context.Context) error {
	// Implement fetching from external API (e.g., Fixer, Open Exchange Rates)
	rates := map[domain.IntCurrency]map[domain.IntCurrency]float64{
		domain.ETB: {
			domain.USD: 0.018,
			domain.EUR: 0.016,
			domain.GBP: 0.014,
		},
		// Add other currencies...
	}

	for from, toRates := range rates {
		for to, rate := range toRates {
			err := s.repo.StoreExchangeRate(ctx, domain.IntCurrencyRate{
				From:       from,
				To:         to,
				Rate:       rate,
				ValidUntil: time.Now().Add(24 * time.Hour), // Refresh daily
			})
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (s *Service) FetchAndStoreRates(ctx context.Context) error {
	// s.logger.Info("Starting exchange rate update")

	rates, err := s.fixerFetcher.FetchLatestRates(ctx, s.baseCurrency)
	if err != nil {
		// s.logger.Error("Failed to fetch rates", "error", err)
		return fmt.Errorf("failed to fetch rates: %w", err)
	}

	// Convert to integer rates with precision
	const precision = 6 // 1.000000
	for currency, rate := range rates {
		if currency == s.baseCurrency {
			continue
		}

		intRate := domain.IntCurrencyRate{
			From:       s.baseCurrency,
			To:         currency,
			Rate:       rate * float64(pow10(precision)),
			ValidUntil: time.Now().Add(24 * time.Hour), // Rates valid for 24 hours
		}

		if err := s.repo.StoreExchangeRate(ctx, intRate); err != nil {
			// s.logger.Error("Failed to store rate",
			// 	"from", s.baseCurrency,
			// 	"to", currency,
			// 	"error", err)
			continue // Try to store other rates even if one fails
		}

		// Also store the inverse rate
		inverseRate := domain.IntCurrencyRate{
			From:       currency,
			To:         s.baseCurrency,
			Rate:       (1 / rate) * float64(pow10(precision)),
			ValidUntil: time.Now().Add(24 * time.Hour),
		}

		if err := s.repo.StoreExchangeRate(ctx, inverseRate); err != nil {
			// s.logger.Error("Failed to store inverse rate",
			// 	"from", currency,
			// 	"to", s.baseCurrency,
			// 	"error", err)
			return fmt.Errorf("Error storing exchange rates")
		}
	}

	// s.logger.Info("Exchange rates updated successfully")
	return nil
}

func pow10(n int) int64 {
	result := int64(1)
	for i := 0; i < n; i++ {
		result *= 10
	}
	return result
}
