package mcp

import (
	"context"
	"fmt"
	"strings"

	"github.com/dtoro/oikos/internal/core/app"
	"github.com/dtoro/oikos/internal/core/ports"
	"github.com/dtoro/oikos/internal/adapters/postgres"
	"github.com/google/uuid"
	"github.com/modelcontextprotocol/go-sdk/mcp"
)

type toolReg struct {
	tool    *mcp.Tool
	handler toolHandler
}

func allTools(pool *db.Pool, agentID uuid.UUID, sec ports.Secrets, entities *app.EntityService, relService *app.RelationshipService) []toolReg {
	return append(append(append(append(
		[]toolReg{},
		EntityTools(pool, agentID, sec, entities, relService)...),
		OpsTools(pool, agentID, sec)...),
		KnowledgeTools(pool, agentID, sec)...),
		AnalysisTools(pool, agentID, sec)...)
}

func formatCheckResult(res app.DeriveResult) string {
	var b strings.Builder
	if res.Created > 0 {
		fmt.Fprintf(&b, " Derived %d check(s).", res.Created)
	}
	if res.Undeclared {
		b.WriteString(" Type declares no monitoring — no checks derived (set the entity's `monitoring` attribute and call update_entity_attributes to regenerate).")
	}
	for _, s := range res.Skipped {
		fmt.Fprintf(&b, " Skipped %s (%s).", s.Kind, s.Reason)
	}
	return b.String()
}

func formatCreateResult(slug, entityType string, res app.DeriveResult) string {
	return fmt.Sprintf("Created %s (%s).%s", slug, entityType, formatCheckResult(res))
}

func rowsToMap(ctx context.Context, pool *db.Pool, query string, args ...any) map[string]any {
	m := map[string]any{}
	rows, err := pool.Query(ctx, query, args...)
	if err != nil {
		return m
	}
	defer rows.Close()
	for rows.Next() {
		var key string
		var val int
		if rows.Scan(&key, &val) == nil {
			m[key] = val
		}
	}
	return m
}

func queryRowsJSONSingle(ctx context.Context, pool *db.Pool, query string, args ...any) []map[string]any {
	rows, err := pool.Query(ctx, query, args...)
	if err != nil {
		return nil
	}
	defer rows.Close()

	cols := rows.FieldDescriptions()
	var items []map[string]any
	for rows.Next() {
		vals, err := rows.Values()
		if err != nil {
			continue
		}
		m := make(map[string]any)
		for i, col := range cols {
			m[string(col.Name)] = fmt.Sprintf("%v", vals[i])
		}
		items = append(items, m)
	}
	return items
}

