package openai

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/rose_cat707/luminary/internal/model"
	"github.com/rose_cat707/luminary/internal/provider"
)

type Client struct {
	http *provider.HTTPClientWrapper
}

func New() *Client {
	return &Client{http: provider.NewHTTPClientWrapper()}
}

func (c *Client) Type() string { return "openai" }

func (c *Client) cfg(baseURL string) provider.ProviderConfig {
	return provider.ProviderConfig{
		Type:     model.ProviderOpenAI,
		Category: model.CategoryLLM,
		BaseURL:  provider.NormalizeBaseURL(baseURL, model.ProviderOpenAI),
	}
}

func (c *Client) ListModels(ctx context.Context, apiKey, baseURL string) ([]provider.ModelInfo, error) {
	return c.ListModelsWithConfig(ctx, apiKey, provider.ProviderConfig{
		Type:    model.ProviderOpenAI,
		BaseURL: provider.NormalizeBaseURL(baseURL, model.ProviderOpenAI),
	})
}

func (c *Client) ListModelsWithConfig(ctx context.Context, apiKey string, cfg provider.ProviderConfig) ([]provider.ModelInfo, error) {
	cfg.Type = model.ProviderOpenAI
	cfg.BaseURL = provider.NormalizeBaseURL(cfg.BaseURL, model.ProviderOpenAI)
	url := cfg.ResolveEndpointURL(provider.EndpointListModels)
	resp, err := provider.ForwardHTTP(ctx, c.http.Client, "GET", url, apiKey, cfg.Type, nil, nil)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("list models: %s", string(resp.Body))
	}
	var out struct {
		Data []struct {
			ID string `json:"id"`
		} `json:"data"`
	}
	if err := json.Unmarshal(resp.Body, &out); err != nil {
		return nil, err
	}
	models := make([]provider.ModelInfo, 0, len(out.Data))
	for _, m := range out.Data {
		models = append(models, provider.ModelInfo{ID: m.ID, DisplayName: m.ID})
	}
	return models, nil
}

func (c *Client) ChatCompletion(ctx context.Context, apiKey, baseURL string, req *provider.ChatRequest) (*provider.ChatResponse, error) {
	return c.ForwardWithConfig(ctx, apiKey, provider.ProviderConfig{
		Type:    model.ProviderOpenAI,
		BaseURL: provider.NormalizeBaseURL(baseURL, model.ProviderOpenAI),
	}, provider.EndpointChatCompletion, req.Raw)
}

func (c *Client) ForwardWithConfig(ctx context.Context, apiKey string, cfg provider.ProviderConfig, endpoint provider.EndpointType, body []byte) (*provider.ChatResponse, error) {
	cfg.Type = model.ProviderOpenAI
	cfg.BaseURL = provider.NormalizeBaseURL(cfg.BaseURL, model.ProviderOpenAI)
	url := cfg.ResolveEndpointURL(endpoint)
	resp, err := provider.ForwardHTTP(ctx, c.http.Client, "POST", url, apiKey, cfg.Type, body, nil)
	if err != nil {
		return nil, err
	}
	return &provider.ChatResponse{
		StatusCode: resp.StatusCode,
		Body:       resp.Body,
		TokensIn:   resp.TokensIn,
		TokensOut:  resp.TokensOut,
	}, nil
}

func (c *Client) HealthCheck(ctx context.Context, apiKey, baseURL string) error {
	_, err := c.ListModels(ctx, apiKey, baseURL)
	return err
}

func (c *Client) HealthCheckWithConfig(ctx context.Context, apiKey string, cfg provider.ProviderConfig) error {
	_, err := c.ListModelsWithConfig(ctx, apiKey, cfg)
	return err
}
