package main

import (
	"context"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/revrost/go-openrouter"
)

type ModelPricing struct {
	Input  float64 `json:"input"`
	Output float64 `json:"output"`
	Image  float64 `json:"image,omitzero"`
}

type Model struct {
	ID          string       `json:"id"`
	Created     int64        `json:"created"`
	Name        string       `json:"name"`
	Description string       `json:"description"`
	Pricing     ModelPricing `json:"pricing"`
	Tags        []string     `json:"tags,omitempty"`

	Reasoning bool `json:"-"`
	Vision    bool `json:"-"`
	JSON      bool `json:"-"`
	Tools     bool `json:"-"`
	Images    bool `json:"-"`
}

var (
	modelMx sync.RWMutex

	ModelMap  map[string]*Model
	ModelList []*Model
)

func GetModel(name string) *Model {
	modelMx.RLock()
	defer modelMx.RUnlock()

	return ModelMap[name]
}

func StartModelUpdateLoop() error {
	err := LoadModels(true)
	if err != nil {
		return err
	}

	go func() {
		ticker := time.NewTicker(2 * time.Hour)

		for range ticker.C {
			err := LoadModels(false)
			if err != nil {
				log.Warnln(err)
			}
		}
	}()

	return nil
}

func LoadModels(initial bool) error {
	log.Println("Refreshing model list...")

	client := OpenRouterClient()

	list, err := client.ListUserModels(context.Background())
	if err != nil {
		return err
	}

	if !initial && len(list) == len(ModelList) {
		log.Println("No new models, skipping update")

		return nil
	}

	sort.Slice(list, func(i, j int) bool {
		return list[i].Created > list[j].Created
	})

	var (
		newList = make([]*Model, len(list))
		newMap  = make(map[string]*Model, len(list))
	)

	for index, model := range list {
		name := model.Name

		if index := strings.Index(name, ": "); index != -1 {
			name = name[index+2:]
		}

		input, _ := strconv.ParseFloat(model.Pricing.Prompt, 64)
		output, _ := strconv.ParseFloat(model.Pricing.Completion, 64)
		image, _ := strconv.ParseFloat(model.Pricing.Image, 64)

		m := &Model{
			ID:          model.ID,
			Created:     model.Created,
			Name:        name,
			Description: model.Description,

			Pricing: ModelPricing{
				Input:  input * 1000000,
				Output: output * 1000000,
				Image:  image,
			},
		}

		GetModelTags(model, m)

		newList[index] = m
		newMap[model.ID] = m
	}

	log.Printf("Loaded %d models\n", len(newList))

	modelMx.Lock()

	ModelList = newList
	ModelMap = newMap

	modelMx.Unlock()

	return nil
}

func GetModelTags(model openrouter.Model, m *Model) {
	for _, parameter := range model.SupportedParameters {
		switch parameter {
		case "reasoning":
			m.Reasoning = true

			m.Tags = append(m.Tags, "reasoning")
		case "response_format":
			m.JSON = true

			m.Tags = append(m.Tags, "json")
		case "tools":
			m.Tools = true

			m.Tags = append(m.Tags, "tools")
		}
	}

	for _, modality := range model.Architecture.InputModalities {
		if modality == "image" {
			m.Vision = true

			m.Tags = append(m.Tags, "vision")
		}
	}

	for _, modality := range model.Architecture.OutputModalities {
		if modality == "image" {
			m.Images = true

			m.Tags = append(m.Tags, "image")
		}
	}

	sort.Strings(m.Tags)
}
