package api

import (
	"database/sql"
	"time"

	"github.com/bigtux/ophion/internal/aiapm"
	"github.com/gofiber/fiber/v2"
)

// AIAPMHandlers holds dependencies for AI APM route handlers
type AIAPMHandlers struct {
	db        *sql.DB
	collector *aiapm.Collector
}

// RegisterAIAPMRoutes registers all AI APM routes on the given router
func RegisterAIAPMRoutes(api fiber.Router, db *sql.DB) *aiapm.Collector {
	collector := aiapm.NewCollector(db, 5000)
	h := &AIAPMHandlers{db: db, collector: collector}

	g := api.Group("/ai-apm")
	g.Post("/ingest", h.Ingest)
	g.Get("/summary", h.Summary)
	g.Get("/models", h.Models)
	g.Get("/vendors", h.Vendors)
	g.Get("/costs", h.Costs)
	g.Get("/calls", h.Calls)
	g.Get("/pricing", h.Pricing)

	return collector
}

// Ingest receives AI call records (single or batch)
func (h *AIAPMHandlers) Ingest(c *fiber.Ctx) error {
	var req aiapm.IngestRequest
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "invalid request body: " + err.Error()})
	}

	count := 0
	if req.Call != nil {
		h.collector.Collect(*req.Call)
		count = 1
	}
	if len(req.Calls) > 0 {
		h.collector.CollectBatch(req.Calls)
		count += len(req.Calls)
	}

	if count == 0 {
		return c.Status(400).JSON(fiber.Map{"error": "no call records provided; use 'call' or 'calls' field"})
	}

	return c.JSON(fiber.Map{"status": "accepted", "count": count})
}

// parseFilter extracts common filter parameters from query string
func parseFilter(c *fiber.Ctx) aiapm.AICallFilter {
	f := aiapm.AICallFilter{
		ServiceName: c.Query("service"),
		ProjectID:   c.Query("project"),
		Vendor:      c.Query("vendor"),
		Model:       c.Query("model"),
		Status:      c.Query("status"),
	}
	if from := c.Query("from"); from != "" {
		if t, err := time.Parse(time.RFC3339, from); err == nil {
			f.From = t
		}
	}
	if to := c.Query("to"); to != "" {
		if t, err := time.Parse(time.RFC3339, to); err == nil {
			f.To = t
		}
	}
	if f.From.IsZero() {
		f.From = time.Now().Add(-24 * time.Hour)
	}
	if f.To.IsZero() {
		f.To = time.Now()
	}
	f.Limit = c.QueryInt("limit", 100)
	f.Offset = c.QueryInt("offset", 0)
	return f
}

// Summary returns aggregated usage statistics
func (h *AIAPMHandlers) Summary(c *fiber.Ctx) error {
	filter := parseFilter(c)
	summary, err := aiapm.GetUsageSummary(h.db, filter)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(summary)
}

// Models returns per-model statistics
func (h *AIAPMHandlers) Models(c *fiber.Ctx) error {
	filter := parseFilter(c)
	stats, err := aiapm.GetModelStats(h.db, filter)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"models": stats})
}

// Vendors returns per-vendor statistics
func (h *AIAPMHandlers) Vendors(c *fiber.Ctx) error {
	filter := parseFilter(c)
	stats, err := aiapm.GetVendorStats(h.db, filter)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"vendors": stats})
}

// Costs returns cost timeseries data
func (h *AIAPMHandlers) Costs(c *fiber.Ctx) error {
	filter := parseFilter(c)
	interval := c.Query("interval", "1d")
	points, err := aiapm.GetCostTimeseries(h.db, filter, interval)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"timeseries": points, "interval": interval})
}

// Calls returns recent AI call records (paginated)
func (h *AIAPMHandlers) Calls(c *fiber.Ctx) error {
	filter := parseFilter(c)
	calls, err := aiapm.QueryCalls(h.db, filter)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"calls": calls, "count": len(calls)})
}

// Pricing returns the current pricing table
func (h *AIAPMHandlers) Pricing(c *fiber.Ctx) error {
	return c.JSON(fiber.Map{"pricing": aiapm.GetPricingTable()})
}
