package ai

import (
	"caltrack/db"
	"caltrack/types"
	"context"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
)

type Client struct {
	cfg *types.Config
	db  *db.DB
}

func New(cfg *types.Config, database *db.DB) *Client {
	return &Client{
		cfg: cfg,
		db:  database,
	}
}

const systemPrompt = `You are a nutrition and exercise expert. Your job is to estimate calories for food items and exercises.

When given a food description, respond with a JSON object containing an "items" array. Each item should have:
- "name": the food item name (e.g., "Banana")
- "brand": brand name if applicable, empty string otherwise
- "kcal": estimated calories (integer)
- "serving_size": the amount (e.g., 1, 200)
- "serving_unit": unit (e.g., "piece", "g", "ml")

When given an exercise description, respond with a JSON object containing an "items" array with a single item:
- "name": the exercise name
- "brand": empty string
- "kcal": estimated calories burned (integer, positive number)
- "serving_size": duration or distance
- "serving_unit": "min" or "km" etc.

For branded products (like "Snickers bar", "Coca Cola 330ml", "Lidl protein pudding"), use real nutritional data.

IMPORTANT: Respond ONLY with valid JSON. No markdown, no explanation, just the JSON object.

Examples:
Input: "ate a banana and a protein shake"
Output: {"items":[{"name":"Banana","brand":"","kcal":105,"serving_size":1,"serving_unit":"piece"},{"name":"Protein shake","brand":"","kcal":250,"serving_size":1,"serving_unit":"serving"}]}

Input: "ran 5k in 25 minutes"
Output: {"items":[{"name":"Running 5K","brand":"","kcal":350,"serving_size":5,"serving_unit":"km"}]}

Input: "Snickers bar"
Output: {"items":[{"name":"Snickers Bar","brand":"Mars","kcal":250,"serving_size":52,"serving_unit":"g"}]}`

func (c *Client) EstimateCalories(ctx context.Context, description string, entryType types.EntryType) (*types.AIEstimation, error) {
	if c.cfg.AnthropicAPIKey == "" {
		return nil, fmt.Errorf("Anthropic API key not configured - go to settings to add it")
	}

	client := anthropic.NewClient(
		option.WithAPIKey(c.cfg.AnthropicAPIKey),
	)

	prompt := fmt.Sprintf("Estimate calories for this %s: %s", entryType, description)

	msg, err := client.Messages.New(ctx, anthropic.MessageNewParams{
		Model:     "claude-haiku-4-5-20251001",
		MaxTokens: 1024,
		System: []anthropic.TextBlockParam{
			{Text: systemPrompt},
		},
		Messages: []anthropic.MessageParam{
			anthropic.NewUserMessage(anthropic.NewTextBlock(prompt)),
		},
	})
	if err != nil {
		return nil, fmt.Errorf("anthropic API error: %w", err)
	}

	if len(msg.Content) == 0 {
		return nil, fmt.Errorf("empty response from API")
	}

	text := msg.Content[0].Text

	// Strip markdown code fences if present
	text = strings.TrimSpace(text)
	if strings.HasPrefix(text, "```") {
		if i := strings.Index(text, "\n"); i != -1 {
			text = text[i+1:]
		}
		if i := strings.LastIndex(text, "```"); i != -1 {
			text = text[:i]
		}
		text = strings.TrimSpace(text)
	}

	var estimation types.AIEstimation
	if err := json.Unmarshal([]byte(text), &estimation); err != nil {
		return nil, fmt.Errorf("failed to parse AI response: %w (response: %s)", err, text)
	}

	// Cache products
	for _, item := range estimation.Items {
		if entryType == types.EntryFood {
			existing, _ := c.db.FindProduct(item.Name, item.Brand)
			if existing == nil {
				c.db.SaveProduct(types.Product{
					Name:           item.Name,
					Brand:          item.Brand,
					ServingSize:    item.ServingSize,
					ServingUnit:    item.ServingUnit,
					KcalPerServing: item.Kcal,
					Source:         "ai",
				})
			}
		}
	}

	return &estimation, nil
}
