package services

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"
)

// SystemAuditLogService is a thin write helper for paliad.system_audit_log
// (mig 102). Each domain emits its own event_type prefix
// (checklist.* / data_export* / …) so dashboards can group by feature.
//
// The audit row is best-effort INSIDE the caller's transaction — the
// caller passes its in-flight *sqlx.Tx so the audit write rolls back
// with the data change if anything else fails.
type SystemAuditLogService struct {
	db *sqlx.DB
}

func NewSystemAuditLogService(db *sqlx.DB) *SystemAuditLogService {
	return &SystemAuditLogService{db: db}
}

// ChecklistAuditEvent is the input shape for the WriteChecklistEvent
// helper. Scope defaults to 'org' since template-level events are firm-
// wide; instance-level events stay on paliad.project_events via the
// existing helpers.
type ChecklistAuditEvent struct {
	EventType  string         // e.g. "checklist.authored", "checklist.edited"
	ActorID    uuid.UUID
	ActorEmail string         // captured at write time; survives user deletion
	Metadata   map[string]any
}

// WriteChecklistEvent inserts a row into paliad.system_audit_log with
// scope='org' and scope_root=NULL. Metadata is JSON-encoded.
func (s *SystemAuditLogService) WriteChecklistEvent(ctx context.Context, tx *sqlx.Tx, evt ChecklistAuditEvent) error {
	if evt.EventType == "" {
		return fmt.Errorf("system_audit_log: event_type required")
	}
	if evt.Metadata == nil {
		evt.Metadata = map[string]any{}
	}
	mb, err := json.Marshal(evt.Metadata)
	if err != nil {
		return fmt.Errorf("system_audit_log marshal: %w", err)
	}
	exec := func(q string, args ...any) error {
		if tx != nil {
			_, err := tx.ExecContext(ctx, q, args...)
			return err
		}
		_, err := s.db.ExecContext(ctx, q, args...)
		return err
	}
	if err := exec(
		`INSERT INTO paliad.system_audit_log
		     (event_type, actor_id, actor_email, scope, scope_root, metadata)
		 VALUES ($1, $2, $3, 'org', NULL, $4::jsonb)`,
		evt.EventType, evt.ActorID, evt.ActorEmail, string(mb),
	); err != nil {
		return fmt.Errorf("system_audit_log insert: %w", err)
	}
	return nil
}
