package observability

import (
	"context"
	"encoding/json"

	"github.com/dtoro/oikos/internal/adapters/postgres/sqlcgen"
	"github.com/google/uuid"
)

// Audit writes an audit_log entry. Pass a transaction-bound Queries so the
// entry commits or rolls back atomically with the state change it records.
//
// actorLabel is the interim textual actor identity ("operator:dev",
// "agent:mcp") recorded in detail; actor_id (a Person/Agent entity UUID)
// starts being populated when OIDC identity resolution lands.
func Audit(ctx context.Context, q *sqlcgen.Queries, actorType, actorLabel,
	action string, entityID *uuid.UUID, method, path, correlationID string,
	sessionID *uuid.UUID, detail map[string]any) error {

	if detail == nil {
		detail = map[string]any{}
	}
	detail["actor"] = actorLabel
	detailJSON, _ := json.Marshal(detail)

	var corr *string
	if correlationID != "" {
		corr = &correlationID
	}
	return q.InsertAuditEntry(ctx, sqlcgen.InsertAuditEntryParams{
		ActorType:     actorType,
		Action:        action,
		EntityID:      entityID,
		Method:        &method,
		Path:          &path,
		Detail:        detailJSON,
		CorrelationID: corr,
		SessionID:     sessionID,
	})
}

// Event emits a structured event in the caller's transaction (SG10). The
// post-commit NOTIFY trigger (migration 008) fans it out to SSE subscribers.
func Event(ctx context.Context, q *sqlcgen.Queries, eventType string,
	entityID *uuid.UUID, severity, source string, correlationID string,
	data map[string]any) error {

	dataJSON, _ := json.Marshal(data)
	if data == nil {
		dataJSON = []byte("{}")
	}
	var corr *string
	if correlationID != "" {
		corr = &correlationID
	}
	_, err := q.InsertEvent(ctx, sqlcgen.InsertEventParams{
		Type:          eventType,
		EntityID:      entityID,
		Severity:      severity,
		Source:        source,
		Data:          dataJSON,
		CorrelationID: corr,
	})
	return err
}
