package usecase

import (
	"context"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	"haixun-backend/internal/model/ai/domain/enum"
	domai "haixun-backend/internal/model/ai/domain/usecase"
	"haixun-backend/internal/model/ai/provider"
)

type UseCase = domai.UseCase

type providerMeta struct {
	ID      string
	Label   string
	Streams bool
}

type aiUseCase struct {
	providers map[enum.ProviderID]domai.Provider
	catalog   []providerMeta
}

func NewUseCase() UseCase {
	providers := map[enum.ProviderID]domai.Provider{
		enum.ProviderOpenCode: provider.NewOpenAICompatible(enum.ProviderOpenCode, "https://opencode.ai/zen/go/v1"),
		enum.ProviderXAI:      provider.NewOpenAICompatible(enum.ProviderXAI, "https://api.x.ai/v1"),
	}
	return &aiUseCase{
		providers: providers,
		catalog: []providerMeta{
			{ID: string(enum.ProviderOpenCode), Label: "OpenCode Go", Streams: true},
			{ID: string(enum.ProviderXAI), Label: "Grok (xAI)", Streams: true},
		},
	}
}

func (u *aiUseCase) ListProviders(ctx context.Context) []domai.ProviderOption {
	options := make([]domai.ProviderOption, 0, len(u.catalog))
	for _, meta := range u.catalog {
		options = append(options, domai.ProviderOption{
			ID:      meta.ID,
			Label:   meta.Label,
			Streams: meta.Streams,
		})
	}
	return options
}

func (u *aiUseCase) ListProviderModels(ctx context.Context, providerID enum.ProviderID, credential domai.Credential) domai.ProviderModels {
	meta, ok := u.meta(providerID)
	if !ok {
		return domai.ProviderModels{
			Error: app.For(code.AI).InputInvalidFormat("unsupported AI provider").Error(),
		}
	}

	result := domai.ProviderModels{
		ID:      meta.ID,
		Label:   meta.Label,
		Models:  []string{},
		Streams: meta.Streams,
	}

	p, ok := u.providers[providerID]
	if !ok {
		result.Error = app.For(code.AI).InputInvalidFormat("unsupported AI provider").Error()
		return result
	}

	models, err := p.ListModels(ctx, credential)
	if err != nil {
		if appErr := app.FromError(err); appErr != nil {
			result.Error = appErr.Error()
		} else {
			result.Error = err.Error()
		}
		return result
	}

	result.Models = models
	return result
}

func (u *aiUseCase) GenerateText(ctx context.Context, req domai.GenerateRequest) (*domai.GenerateResult, error) {
	p, err := u.resolve(req.Provider)
	if err != nil {
		return nil, err
	}
	return p.GenerateText(ctx, req)
}

func (u *aiUseCase) StreamText(ctx context.Context, req domai.GenerateRequest) (<-chan domai.StreamEvent, error) {
	p, err := u.resolve(req.Provider)
	if err != nil {
		return nil, err
	}
	return p.StreamText(ctx, req)
}

func (u *aiUseCase) meta(id enum.ProviderID) (providerMeta, bool) {
	for _, meta := range u.catalog {
		if meta.ID == string(id) {
			return meta, true
		}
	}
	return providerMeta{}, false
}

func (u *aiUseCase) resolve(id enum.ProviderID) (domai.Provider, error) {
	p, ok := u.providers[id]
	if !ok {
		return nil, app.For(code.AI).InputInvalidFormat("unsupported AI provider")
	}
	return p, nil
}
