package templates

import (
	"fmt"
	"portfolio-tracker/internal/model"
	"portfolio-tracker/internal/util"
	"time"
)

// calculateTotalInvested calculates the total amount invested (buy transactions)
func calculateTotalInvested(activities []model.Activity) float64 {
	var total float64 = 0
	for _, activity := range activities {
		if activity.Type == model.Buy {
			total += activity.Amount * activity.Price
		}
	}
	return total
}

// calculateTotalInvestedInBaseCurrency calculates total invested converted to portfolio base currency using historical rates
func calculateTotalInvestedInBaseCurrency(activities []model.Activity, baseCurrency string) float64 {
	var total float64 = 0
	for _, activity := range activities {
		if activity.Type == model.Buy {
			activityTotal := activity.Amount * activity.Price

			if activity.Currency == baseCurrency {
				total += activityTotal
			} else {
				// Use historical exchange rate for the transaction date
				convertedTotal, err := util.ConvertCurrencyHistorical(activityTotal, activity.Currency, baseCurrency, activity.Date)
				if err != nil {
					// If historical conversion fails, try current rate as fallback
					fallbackTotal, fallbackErr := util.ConvertCurrency(activityTotal, activity.Currency, baseCurrency)
					if fallbackErr != nil {
						// If all conversions fail, add original amount (last resort)
						total += activityTotal
					} else {
						total += fallbackTotal
					}
				} else {
					total += convertedTotal
				}
			}
		}
	}
	return total
}

// getLastBuyDate returns the date of the last buy transaction
func getLastBuyDate(activities []model.Activity) string {
	var lastBuy time.Time
	for _, activity := range activities {
		if activity.Type == model.Buy && activity.Date.After(lastBuy) {
			lastBuy = activity.Date
		}
	}
	if lastBuy.IsZero() {
		return "Keine Käufe"
	}
	return lastBuy.Format("02.01.2006")
}

// convertActivityPrice converts activity price to portfolio base currency using historical rate
func convertActivityPrice(activity model.Activity, portfolioBaseCurrency string) (float64, string, error) {
	if activity.Currency == portfolioBaseCurrency {
		return activity.Price, "", nil // No conversion needed
	}

	convertedPrice, err := util.ConvertCurrencyHistorical(activity.Price, activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return 0, "", err
	}

	return convertedPrice, portfolioBaseCurrency, nil
}

// formatActivityPrice formats activity price with conversion if needed using historical rates
func formatActivityPrice(activity model.Activity, portfolioBaseCurrency string) string {
	if activity.Currency == portfolioBaseCurrency {
		return fmt.Sprintf("%.2f %s", activity.Price, activity.Currency)
	}

	convertedPrice, err := util.ConvertCurrencyHistorical(activity.Price, activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return fmt.Sprintf("%.2f %s (conv. error)", activity.Price, activity.Currency)
	}

	return fmt.Sprintf("%.2f %s (~%.2f %s)", activity.Price, activity.Currency, convertedPrice, portfolioBaseCurrency)
}

// formatActivityTotal formats activity total with conversion if needed using historical rates
func formatActivityTotal(activity model.Activity, portfolioBaseCurrency string) string {
	total := activity.Amount * activity.Price

	if activity.Currency == portfolioBaseCurrency {
		return fmt.Sprintf("%.2f %s", total, activity.Currency)
	}

	convertedTotal, err := util.ConvertCurrencyHistorical(total, activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return fmt.Sprintf("%.2f %s (conv. error)", total, activity.Currency)
	}

	return fmt.Sprintf("%.2f %s (~%.2f %s)", total, activity.Currency, convertedTotal, portfolioBaseCurrency)
}

// getConvertedPrice returns the converted price using historical exchange rate or original if conversion fails
func getConvertedPrice(activity model.Activity, portfolioBaseCurrency string) string {
	if activity.Currency == portfolioBaseCurrency {
		return ""
	}

	// Use historical exchange rate for the transaction date
	convertedPrice, isHistorical, err := util.GetExchangeRateWithFallback(activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return "Conv. Error"
	}

	finalPrice := activity.Price * convertedPrice

	// Add indicator if fallback (current) rate was used instead of historical
	if !isHistorical {
		return fmt.Sprintf("%.2f %s*", finalPrice, portfolioBaseCurrency)
	}

	return fmt.Sprintf("%.2f %s", finalPrice, portfolioBaseCurrency)
}

// getConvertedTotal returns the converted total using historical exchange rate or original if conversion fails
func getConvertedTotal(activity model.Activity, portfolioBaseCurrency string) string {
	if activity.Currency == portfolioBaseCurrency {
		return ""
	}

	total := activity.Amount * activity.Price

	// Use historical exchange rate for the transaction date
	convertedTotal, err := util.ConvertCurrencyHistorical(total, activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return "Conv. Error"
	}

	return fmt.Sprintf("%.2f %s", convertedTotal, portfolioBaseCurrency)
}

// getConvertedTotalWithFallbackInfo returns the converted total with information about rate source
func getConvertedTotalWithFallbackInfo(activity model.Activity, portfolioBaseCurrency string) string {
	if activity.Currency == portfolioBaseCurrency {
		return ""
	}

	total := activity.Amount * activity.Price

	// Use historical exchange rate with fallback information
	rate, isHistorical, err := util.GetExchangeRateWithFallback(activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return "Conv. Error"
	}

	convertedTotal := total * rate

	// Add indicator if fallback (current) rate was used instead of historical
	if !isHistorical {
		return fmt.Sprintf("%.2f %s*", convertedTotal, portfolioBaseCurrency)
	}

	return fmt.Sprintf("%.2f %s", convertedTotal, portfolioBaseCurrency)
}

// formatTotalInvestedWithConversion formats total invested with currency info and conversion indicators
func formatTotalInvestedWithConversion(activities []model.Activity, baseCurrency string) string {
	convertedTotal := calculateTotalInvestedInBaseCurrency(activities, baseCurrency)

	// Check if any activities have different currencies
	hasDifferentCurrencies := false
	hasHistoricalConversions := false

	for _, activity := range activities {
		if activity.Type == model.Buy && activity.Currency != baseCurrency {
			hasDifferentCurrencies = true

			// Check if we can get historical rate for this transaction
			_, isHistorical, err := util.GetExchangeRateWithFallback(activity.Currency, baseCurrency, activity.Date)
			if err == nil && isHistorical {
				hasHistoricalConversions = true
			}
			break
		}
	}

	if !hasDifferentCurrencies {
		return fmt.Sprintf("%.2f %s", convertedTotal, baseCurrency)
	}

	if hasHistoricalConversions {
		return fmt.Sprintf("%.2f %s (historical rates)", convertedTotal, baseCurrency)
	}

	return fmt.Sprintf("%.2f %s (converted)", convertedTotal, baseCurrency)
}

// calculateTotalInvestedByDate calculates total invested up to a specific date
func calculateTotalInvestedByDate(activities []model.Activity, baseCurrency string, endDate time.Time) float64 {
	var total float64 = 0
	for _, activity := range activities {
		if activity.Type == model.Buy && activity.Date.Before(endDate.AddDate(0, 0, 1)) { // Include transactions on endDate
			activityTotal := activity.Amount * activity.Price

			if activity.Currency == baseCurrency {
				total += activityTotal
			} else {
				// Use historical exchange rate for the transaction date
				convertedTotal, err := util.ConvertCurrencyHistorical(activityTotal, activity.Currency, baseCurrency, activity.Date)
				if err != nil {
					// If historical conversion fails, try current rate as fallback
					fallbackTotal, fallbackErr := util.ConvertCurrency(activityTotal, activity.Currency, baseCurrency)
					if fallbackErr != nil {
						// If all conversions fail, add original amount (last resort)
						total += activityTotal
					} else {
						total += fallbackTotal
					}
				} else {
					total += convertedTotal
				}
			}
		}
	}
	return total
}

// getConversionInfo returns information about currency conversions used in the portfolio
func getConversionInfo(activities []model.Activity, baseCurrency string) map[string]interface{} {
	info := map[string]interface{}{
		"hasDifferentCurrencies": false,
		"historicalConversions":  0,
		"fallbackConversions":    0,
		"errorConversions":       0,
		"currencies":             make(map[string]int),
	}

	currencies := make(map[string]int)
	historicalCount := 0
	fallbackCount := 0
	errorCount := 0

	for _, activity := range activities {
		if activity.Type == model.Buy {
			currencies[activity.Currency]++

			if activity.Currency != baseCurrency {
				info["hasDifferentCurrencies"] = true

				// Check conversion status
				_, isHistorical, err := util.GetExchangeRateWithFallback(activity.Currency, baseCurrency, activity.Date)
				if err != nil {
					errorCount++
				} else if isHistorical {
					historicalCount++
				} else {
					fallbackCount++
				}
			}
		}
	}

	info["historicalConversions"] = historicalCount
	info["fallbackConversions"] = fallbackCount
	info["errorConversions"] = errorCount
	info["currencies"] = currencies

	return info
}

// formatCurrencyWithConversionNote formats currency amount with appropriate conversion notes
func formatCurrencyWithConversionNote(amount float64, fromCurrency, toCurrency string, transactionDate time.Time) string {
	if fromCurrency == toCurrency {
		return util.FormatCurrencyWithSymbol(amount, toCurrency)
	}

	rate, isHistorical, err := util.GetExchangeRateWithFallback(fromCurrency, toCurrency, transactionDate)
	if err != nil {
		return fmt.Sprintf("%.2f %s (conv. error)", amount, fromCurrency)
	}

	convertedAmount := amount * rate

	if isHistorical {
		return fmt.Sprintf("%.2f %s (historical rate)", convertedAmount, toCurrency)
	}

	return fmt.Sprintf("%.2f %s (current rate)", convertedAmount, toCurrency)
}

// getActivityConversionStatus returns the conversion status for a specific activity
func getActivityConversionStatus(activity model.Activity, portfolioBaseCurrency string) string {
	if activity.Currency == portfolioBaseCurrency {
		return "same_currency"
	}

	_, isHistorical, err := util.GetExchangeRateWithFallback(activity.Currency, portfolioBaseCurrency, activity.Date)
	if err != nil {
		return "error"
	}

	if isHistorical {
		return "historical"
	}

	return "fallback"
}
