package gateway

import (
	"strings"

	"github.com/rose_cat707/luminary/internal/model"
	"github.com/rose_cat707/luminary/internal/store/cache"
)

type routeTarget struct {
	ProviderID    uint
	ProviderKeyID uint // 0 = auto load balance
}

func (s *Service) resolveRoute(ingressID uint, modelName string) *routeTarget {
	rules := s.cache.ListRoutingRules(ingressID)
	var best *model.RoutingRule
	for i := range rules {
		r := rules[i]
		if !r.Enabled {
			continue
		}
		if !matchPattern(r.ModelPattern, modelName) {
			continue
		}
		if best == nil || r.Priority > best.Priority {
			best = &r
		}
	}
	if best == nil {
		return nil
	}
	return &routeTarget{ProviderID: best.ProviderID, ProviderKeyID: best.ProviderKeyID}
}

func matchPattern(pattern, model string) bool {
	if pattern == "" || pattern == "*" {
		return true
	}
	if strings.HasSuffix(pattern, "*") {
		return strings.HasPrefix(model, strings.TrimSuffix(pattern, "*"))
	}
	return pattern == model
}

func (s *Service) findProvidersForModel(modelName string, allowed []string, category model.ProviderCategory, route *routeTarget) ([]model.Provider, error) {
	if route != nil {
		if p, ok := s.cache.GetProvider(route.ProviderID); ok && p.Category == category && p.Enabled {
			if cache.MatchesList(allowed, p.Name) || cache.MatchesList(allowed, string(p.Type)) || cache.MatchesList(allowed, "*") {
				return []model.Provider{p}, nil
			}
		}
	}
	var matched []model.Provider
	for _, p := range s.cache.ListProviders() {
		if p.Category != category || !model.IsCategorySupported(p.Category) || !p.Enabled {
			continue
		}
		if !cache.MatchesList(allowed, p.Name) && !cache.MatchesList(allowed, string(p.Type)) {
			continue
		}
		if s.providerSupportsModel(&p, modelName) {
			matched = append(matched, p)
		}
	}
	if len(matched) == 0 {
		if parts := strings.SplitN(modelName, "/", 2); len(parts) == 2 {
			if p, ok := s.cache.GetProviderByName(parts[0]); ok && p.Category == category && p.Enabled {
				if s.providerSupportsModel(&p, parts[1]) {
					return []model.Provider{p}, nil
				}
			}
		}
		return nil, errNoProvider(modelName)
	}
	return matched, nil
}

func (s *Service) providerSupportsModel(p *model.Provider, modelName string) bool {
	models := s.cache.GetModels(p.ID)
	if len(models) == 0 {
		for _, k := range s.cache.ListProviderKeys(p.ID) {
			allowed := cache.ParseJSONList(k.ModelsJSON)
			if cache.MatchesList(allowed, modelName) || cache.MatchesList(allowed, "*") {
				return true
			}
		}
		return false
	}
	for _, m := range models {
		if m.Enabled && modelEntryMatches(m, modelName) {
			return true
		}
	}
	return false
}

func errNoProvider(model string) error {
	return &gatewayError{msg: "no provider found for model " + model}
}

type gatewayError struct{ msg string }

func (e *gatewayError) Error() string { return e.msg }
