package embedclient

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
)

type googleClient struct {
	baseURL    string
	apiKey     string
	model      string
	httpClient *http.Client
}

// NewGoogle returns a Client that speaks the Google Gemini batchEmbedContents API.
func NewGoogle(baseURL, apiKey, model string, httpClient *http.Client) Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	return &googleClient{baseURL: baseURL, apiKey: apiKey, model: model, httpClient: httpClient}
}

type googleBatchRequest struct {
	Requests []googleEmbedRequest `json:"requests"`
}

type googleEmbedRequest struct {
	Model   string        `json:"model"`
	Content googleContent `json:"content"`
}

type googleContent struct {
	Parts []googlePart `json:"parts"`
}

type googlePart struct {
	Text string `json:"text"`
}

type googleBatchResponse struct {
	Embeddings []struct {
		Values []float32 `json:"values"`
	} `json:"embeddings"`
}

func (c *googleClient) Embed(ctx context.Context, req Request) (Response, error) {
	requests := make([]googleEmbedRequest, len(req.Texts))
	for i, text := range req.Texts {
		requests[i] = googleEmbedRequest{
			Model:   "models/" + c.model,
			Content: googleContent{Parts: []googlePart{{Text: text}}},
		}
	}

	body, err := json.Marshal(googleBatchRequest{Requests: requests})
	if err != nil {
		return Response{}, fmt.Errorf("google embed marshal: %w", err)
	}

	url := fmt.Sprintf("%s/v1/models/%s:batchEmbedContents", c.baseURL, c.model)
	if c.apiKey != "" {
		url += "?key=" + c.apiKey
	}

	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
	if err != nil {
		return Response{}, fmt.Errorf("google embed request: %w", err)
	}
	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(httpReq)
	if err != nil {
		return Response{}, fmt.Errorf("google embed do: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

	if resp.StatusCode != http.StatusOK {
		return Response{}, fmt.Errorf("google embed: unexpected status %d", resp.StatusCode)
	}

	var gResp googleBatchResponse
	if err := json.NewDecoder(resp.Body).Decode(&gResp); err != nil {
		return Response{}, fmt.Errorf("google embed decode: %w", err)
	}

	embeddings := make([][]float32, len(gResp.Embeddings))
	for i, e := range gResp.Embeddings {
		embeddings[i] = e.Values
	}

	return Response{
		Embeddings: embeddings,
		Model:      c.model,
	}, nil
}
