package service

import (
	"ai_scheduler/internal/config"
	"ai_scheduler/internal/domain/llm"
	"ai_scheduler/internal/domain/llm/capability"
	"ai_scheduler/internal/domain/llm/provider"
	"context"

	"github.com/cloudwego/eino/schema"
)

type LLMService struct{ cfg *config.Config }

func NewLLMService(cfg *config.Config) *LLMService { return &LLMService{cfg: cfg} }

func (s *LLMService) Chat(ctx context.Context, input []*schema.Message, opts llm.Options) (*schema.Message, error) {
	choice, routeOpts, err := capability.Route(s.cfg, capability.Chat)
	if err != nil {
		return nil, err
	}
	mergeOptions(&routeOpts, opts)
	f := provider.Get(choice.Provider)
	if f == nil {
		return nil, llm.ErrProviderNotFound
	}
	return f().Generate(ctx, input, routeOpts)
}

func (s *LLMService) ChatStream(ctx context.Context, input []*schema.Message, opts llm.Options) (*schema.StreamReader[*schema.Message], error) {
	choice, routeOpts, err := capability.Route(s.cfg, capability.Chat)
	if err != nil {
		return nil, err
	}
	routeOpts.Stream = true
	mergeOptions(&routeOpts, opts)
	f := provider.Get(choice.Provider)
	if f == nil {
		return nil, llm.ErrProviderNotFound
	}
	return f().Stream(ctx, input, routeOpts)
}

func (s *LLMService) Vision(ctx context.Context, input []*schema.Message, opts llm.Options) (*schema.Message, error) {
	choice, routeOpts, err := capability.Route(s.cfg, capability.Vision)
	if err != nil {
		return nil, err
	}
	mergeOptions(&routeOpts, opts)
	f := provider.Get(choice.Provider)
	if f == nil {
		return nil, llm.ErrProviderNotFound
	}
	return f().Generate(ctx, input, routeOpts)
}

func (s *LLMService) Intent(ctx context.Context, input []*schema.Message, opts llm.Options) (*schema.Message, error) {
	choice, routeOpts, err := capability.Route(s.cfg, capability.Intent)
	if err != nil {
		return nil, err
	}
	mergeOptions(&routeOpts, opts)
	f := provider.Get(choice.Provider)
	if f == nil {
		return nil, llm.ErrProviderNotFound
	}
	return f().Generate(ctx, input, routeOpts)
}

func mergeOptions(base *llm.Options, override llm.Options) {
	if override.Model != "" {
		base.Model = override.Model
	}
	if override.MaxTokens > 0 {
		base.MaxTokens = override.MaxTokens
	}
	if override.Temperature != 0 {
		base.Temperature = override.Temperature
	}
	if override.Timeout > 0 {
		base.Timeout = override.Timeout
	}
	if len(override.Modalities) > 0 {
		base.Modalities = override.Modalities
	}
	if override.SystemPrompt != "" {
		base.SystemPrompt = override.SystemPrompt
	}
	if override.TopP != 0 {
		base.TopP = override.TopP
	}
	if len(override.Stop) > 0 {
		base.Stop = override.Stop
	}
	base.Stream = base.Stream || override.Stream
}
