package utils

import (
	"fmt"
	"math"

	"pluja.dev/kycnot.me/database"
)

func ComputeScore(s *database.Service) (int, string) {
	summary := fmt.Sprintf("SCORE BREAKDOWN - %s:\n", s.Name)
	summary += "\n||-----------------------------------------------"

	grade := float64(10)

	// KYC Level Adjustment
	switch s.KycLevel {
	case 0:
		grade = 8
		summary += fmt.Sprintf("\n%-*s--> base score for KYC Level %d", 10, fmt.Sprintf("|| %v", grade), s.KycLevel)
	case 1:
		grade = 7
		summary += fmt.Sprintf("\n%-*s--> base score for KYC Level %d", 10, fmt.Sprintf("|| %v", grade), s.KycLevel)
	case 2:
		grade = 6
		summary += fmt.Sprintf("\n%-*s--> base score for KYC Level %d", 10, fmt.Sprintf("|| %v", grade), s.KycLevel)
	case 3:
		grade = 5
		summary += fmt.Sprintf("\n%-*s--> base score for KYC Level %d", 10, fmt.Sprintf("|| %v", grade), s.KycLevel)
	}

	// Attributes
	for _, attr := range s.Expand["attributes"] {
		switch attr.Rating {
		case "good":
			grade += 0.1
			summary += fmt.Sprintf("\n%-*s--> good attribute.", 10, "|| +0.1")
		case "warn":
			grade -= 0.25
			summary += fmt.Sprintf("\n%-*s--> warn attribute.", 10, "|| -0.25")
		case "bad":
			grade -= 0.65
			summary += fmt.Sprintf("\n%-*s--> bad attribute.", 10, "|| -0.65")
		}
	}

	// Tos Highlights Penalty
	if s.TosReviews == nil {
		s.TosReviews = []database.TosReview{}
	}

	trPenalty := 0.0
	wrns := 0
	for _, tr := range s.TosReviews {
		if tr.Warning {
			trPenalty -= 0.02
			wrns++
		}
	}

	if trPenalty > 3 {
		trPenalty = 3
	}

	grade += float64(trPenalty)

	if trPenalty != 0 {
		summary += fmt.Sprintf("\n|| %-*f--> %d terms of service warnings.", 10, trPenalty, wrns)
	}

	// Cash/Monero Bonus
	if s.Cash || s.Xmr || s.Btc {
		grade += 0.25
		summary += fmt.Sprintf("\n%-*s--> accepting Cash/BTC.", 10, "|| +0.25")
		if s.Xmr {
			grade += 0.25
			summary += fmt.Sprintf("\n%-*s--> accepting XMR.", 10, "|| +0.25")
		}
	}

	// TODO: Manage bonuses
	// P2P/OpenSource Bonus
	isP2P := false
	isOpenSource := false
	for _, attr := range s.Attributes {
		if attr == database.AttributeP2P {
			isP2P = true
		}
		if attr == database.AttributeOpenSource {
			isOpenSource = true
		}
	}

	// Tor URL Bonus
	if len(s.OnionUrls) > 0 && s.OnionUrls[0] != "" {
		grade += 0.5
		summary += fmt.Sprintf("\n%-*s--> has Onion links.", 10, "|| +0.5")
	}

	if s.Verified {
		if grade < 7.5 {
			grade += 0.5
			summary += fmt.Sprintf("\n%-*s--> verified bonus (only if <7.5).", 10, "|| +0.5")
		}
	}

	if !isP2P && grade > 9.5 {
		grade = 9
		summary += fmt.Sprintf("\n%-*s--> Not P2P, score can't be 10.", 10, "|| ----")
	}

	if isP2P {
		grade += 0.5
		summary += fmt.Sprintf("\n%-*s--> P2P bonus.", 10, "|| +0.5")
	}

	if isOpenSource && grade < 7.5 {
		grade += 0.25
		summary += fmt.Sprintf("\n%-*s--> Open Source bonus (if < 7.5).", 10, "|| +0.25")
	}

	// Normalize the grade to be within 0-10 bounds
	grade = math.Min(10, math.Max(0, grade))

	summary += "\n||-----------------------------------------------"

	summary += fmt.Sprintf("\n||  %-*v--> Total (rounded to even)", 6, math.RoundToEven(grade)) // Call ComputeScore to get the actual score
	summary += "\n||-----------------------------------------------"

	summary += "\n\n\nCheck out the score algorithm here: https://github.com/pluja/kycnot.me\nIf you think there's a better way to compute score, please, open an issue with your ideas."

	return int(math.RoundToEven(grade)), summary
}

/*func UpdateScore(s *ent.Service) error {
	score := ComputeScore(s)
	ctx := context.Background()
	_, err := database.Client.Service.UpdateOneID(s.ID).SetScore(score).Save(ctx)
	return err
}*/
