// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.29.0
// source: operations.sql

package sqlcgen

import (
	"context"
	"time"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgtype"
)

const getApprovalByID = `-- name: GetApprovalByID :one
SELECT entity_id, subject_entity_id, action, risk_class, kind, payload, status, token_hash, expires_at, decided_at, decided_by, created_at, matrix_event_id, alert_sent_at FROM approvals WHERE entity_id = $1
`

func (q *Queries) GetApprovalByID(ctx context.Context, entityID uuid.UUID) (Approval, error) {
	row := q.db.QueryRow(ctx, getApprovalByID, entityID)
	var i Approval
	err := row.Scan(
		&i.EntityID,
		&i.SubjectEntityID,
		&i.Action,
		&i.RiskClass,
		&i.Kind,
		&i.Payload,
		&i.Status,
		&i.TokenHash,
		&i.ExpiresAt,
		&i.DecidedAt,
		&i.DecidedBy,
		&i.CreatedAt,
		&i.MatrixEventID,
		&i.AlertSentAt,
	)
	return i, err
}

const getAutonomySetting = `-- name: GetAutonomySetting :one
SELECT value FROM autonomy_settings WHERE key = $1
`

func (q *Queries) GetAutonomySetting(ctx context.Context, key string) (string, error) {
	row := q.db.QueryRow(ctx, getAutonomySetting, key)
	var value string
	err := row.Scan(&value)
	return value, err
}

const getCheckDef = `-- name: GetCheckDef :one
SELECT entity_id, target_id, target_type, kind, config, interval_s, timeout_s, zone, enabled, updated_at, last_run_at, last_health FROM check_defs WHERE entity_id = $1
`

func (q *Queries) GetCheckDef(ctx context.Context, entityID uuid.UUID) (CheckDef, error) {
	row := q.db.QueryRow(ctx, getCheckDef, entityID)
	var i CheckDef
	err := row.Scan(
		&i.EntityID,
		&i.TargetID,
		&i.TargetType,
		&i.Kind,
		&i.Config,
		&i.IntervalS,
		&i.TimeoutS,
		&i.Zone,
		&i.Enabled,
		&i.UpdatedAt,
		&i.LastRunAt,
		&i.LastHealth,
	)
	return i, err
}

const getEntityStatus = `-- name: GetEntityStatus :one
SELECT entity_id, health, last_check_at, details, updated_at FROM entity_status WHERE entity_id = $1
`

func (q *Queries) GetEntityStatus(ctx context.Context, entityID uuid.UUID) (EntityStatus, error) {
	row := q.db.QueryRow(ctx, getEntityStatus, entityID)
	var i EntityStatus
	err := row.Scan(
		&i.EntityID,
		&i.Health,
		&i.LastCheckAt,
		&i.Details,
		&i.UpdatedAt,
	)
	return i, err
}

const getExecution = `-- name: GetExecution :one
SELECT entity_id, classification_id, signal_entity_id, target_entity_id, action, risk_class, approval_id, agent_id, skill_id, skill_version, status, result, duration_ms, verified, correlation_id, started_at, completed_at, created_at FROM executions WHERE entity_id = $1
`

func (q *Queries) GetExecution(ctx context.Context, entityID uuid.UUID) (Execution, error) {
	row := q.db.QueryRow(ctx, getExecution, entityID)
	var i Execution
	err := row.Scan(
		&i.EntityID,
		&i.ClassificationID,
		&i.SignalEntityID,
		&i.TargetEntityID,
		&i.Action,
		&i.RiskClass,
		&i.ApprovalID,
		&i.AgentID,
		&i.SkillID,
		&i.SkillVersion,
		&i.Status,
		&i.Result,
		&i.DurationMs,
		&i.Verified,
		&i.CorrelationID,
		&i.StartedAt,
		&i.CompletedAt,
		&i.CreatedAt,
	)
	return i, err
}

const getFeedbackAfterWatermark = `-- name: GetFeedbackAfterWatermark :many
SELECT f.entity_id, f.execution_id, f.outcome, f.observation, f.lesson,
       f.unexpected_side_effects, f.tags, f.created_at,
       e.action, e.risk_class, e.target_entity_id,
       et.name AS applies_type
FROM feedback f
JOIN executions e ON e.entity_id = f.execution_id
JOIN entities ent ON ent.id = e.target_entity_id
JOIN entity_types et ON et.name = ent.type
WHERE f.created_at > $1
ORDER BY f.created_at ASC
`

type GetFeedbackAfterWatermarkRow struct {
	EntityID              uuid.UUID
	ExecutionID           uuid.UUID
	Outcome               string
	Observation           *string
	Lesson                *string
	UnexpectedSideEffects []string
	Tags                  []string
	CreatedAt             time.Time
	Action                string
	RiskClass             string
	TargetEntityID        *uuid.UUID
	AppliesType           string
}

func (q *Queries) GetFeedbackAfterWatermark(ctx context.Context, createdAt time.Time) ([]GetFeedbackAfterWatermarkRow, error) {
	rows, err := q.db.Query(ctx, getFeedbackAfterWatermark, createdAt)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetFeedbackAfterWatermarkRow
	for rows.Next() {
		var i GetFeedbackAfterWatermarkRow
		if err := rows.Scan(
			&i.EntityID,
			&i.ExecutionID,
			&i.Outcome,
			&i.Observation,
			&i.Lesson,
			&i.UnexpectedSideEffects,
			&i.Tags,
			&i.CreatedAt,
			&i.Action,
			&i.RiskClass,
			&i.TargetEntityID,
			&i.AppliesType,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getIdempotentResponse = `-- name: GetIdempotentResponse :one
SELECT response_code, response_body, request_hash FROM idempotency_keys
WHERE actor = $1 AND key = $2
`

type GetIdempotentResponseParams struct {
	Actor string
	Key   string
}

type GetIdempotentResponseRow struct {
	ResponseCode *int32
	ResponseBody []byte
	RequestHash  string
}

func (q *Queries) GetIdempotentResponse(ctx context.Context, arg GetIdempotentResponseParams) (GetIdempotentResponseRow, error) {
	row := q.db.QueryRow(ctx, getIdempotentResponse, arg.Actor, arg.Key)
	var i GetIdempotentResponseRow
	err := row.Scan(&i.ResponseCode, &i.ResponseBody, &i.RequestHash)
	return i, err
}

const getOpenSignalsForAutoAct = `-- name: GetOpenSignalsForAutoAct :many
SELECT s.entity_id, s.kind, s.severity, s.target_entity_id, s.check_id, s.evidence, s.likely_cause, s.state, s.occurrence_count, s.first_seen_at, s.last_seen_at, s.flap_count, s.hold_down_until, s.mute_until, s.created_at, s.updated_at, c.entity_id AS classification_id, c.action, c.risk_class, c.route,
       c.blast_radius, c.correlation_id, c.reasoning
FROM classifications c
JOIN signals s ON s.entity_id = c.signal_entity_id
LEFT JOIN executions e ON e.classification_id = c.entity_id
WHERE c.route = 'auto-act'
  AND e.entity_id IS NULL
  AND (s.hold_down_until IS NULL OR s.hold_down_until < now())
  AND (s.mute_until IS NULL OR s.mute_until < now())
ORDER BY s.last_seen_at ASC
LIMIT $1
`

type GetOpenSignalsForAutoActRow struct {
	EntityID         uuid.UUID
	Kind             string
	Severity         string
	TargetEntityID   *uuid.UUID
	CheckID          *uuid.UUID
	Evidence         *string
	LikelyCause      *string
	State            string
	OccurrenceCount  int32
	FirstSeenAt      time.Time
	LastSeenAt       time.Time
	FlapCount        int32
	HoldDownUntil    *time.Time
	MuteUntil        *time.Time
	CreatedAt        time.Time
	UpdatedAt        time.Time
	ClassificationID uuid.UUID
	Action           string
	RiskClass        string
	Route            string
	BlastRadius      []uuid.UUID
	CorrelationID    string
	Reasoning        []byte
}

// Signals with auto-act classifications that haven't been executed yet
func (q *Queries) GetOpenSignalsForAutoAct(ctx context.Context, limit int32) ([]GetOpenSignalsForAutoActRow, error) {
	rows, err := q.db.Query(ctx, getOpenSignalsForAutoAct, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetOpenSignalsForAutoActRow
	for rows.Next() {
		var i GetOpenSignalsForAutoActRow
		if err := rows.Scan(
			&i.EntityID,
			&i.Kind,
			&i.Severity,
			&i.TargetEntityID,
			&i.CheckID,
			&i.Evidence,
			&i.LikelyCause,
			&i.State,
			&i.OccurrenceCount,
			&i.FirstSeenAt,
			&i.LastSeenAt,
			&i.FlapCount,
			&i.HoldDownUntil,
			&i.MuteUntil,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.ClassificationID,
			&i.Action,
			&i.RiskClass,
			&i.Route,
			&i.BlastRadius,
			&i.CorrelationID,
			&i.Reasoning,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getPattern = `-- name: GetPattern :one
SELECT entity_id, applies_type, action, pattern, confidence, evidence_count, success_count, failure_count, status, quarantined, version, last_validated_at, created_at FROM patterns WHERE applies_type = $1 AND action = $2
`

type GetPatternParams struct {
	AppliesType string
	Action      string
}

func (q *Queries) GetPattern(ctx context.Context, arg GetPatternParams) (Pattern, error) {
	row := q.db.QueryRow(ctx, getPattern, arg.AppliesType, arg.Action)
	var i Pattern
	err := row.Scan(
		&i.EntityID,
		&i.AppliesType,
		&i.Action,
		&i.Pattern,
		&i.Confidence,
		&i.EvidenceCount,
		&i.SuccessCount,
		&i.FailureCount,
		&i.Status,
		&i.Quarantined,
		&i.Version,
		&i.LastValidatedAt,
		&i.CreatedAt,
	)
	return i, err
}

const insertApproval = `-- name: InsertApproval :exec
INSERT INTO approvals (entity_id, subject_entity_id, action, risk_class, kind,
    payload, status, token_hash, expires_at)
VALUES ($1, $2, $3, $4, $5, $6, 'pending', $7, $8)
`

type InsertApprovalParams struct {
	EntityID        uuid.UUID
	SubjectEntityID *uuid.UUID
	Action          string
	RiskClass       string
	Kind            string
	Payload         []byte
	TokenHash       *string
	ExpiresAt       time.Time
}

func (q *Queries) InsertApproval(ctx context.Context, arg InsertApprovalParams) error {
	_, err := q.db.Exec(ctx, insertApproval,
		arg.EntityID,
		arg.SubjectEntityID,
		arg.Action,
		arg.RiskClass,
		arg.Kind,
		arg.Payload,
		arg.TokenHash,
		arg.ExpiresAt,
	)
	return err
}

const insertAuditEntry = `-- name: InsertAuditEntry :exec
INSERT INTO audit_log (actor_type, actor_id, action, entity_id, method, path,
                       status_code, detail, source_ip, correlation_id, session_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
`

type InsertAuditEntryParams struct {
	ActorType     string
	ActorID       *uuid.UUID
	Action        string
	EntityID      *uuid.UUID
	Method        *string
	Path          *string
	StatusCode    *int32
	Detail        []byte
	SourceIp      *string
	CorrelationID *string
	SessionID     *uuid.UUID
}

func (q *Queries) InsertAuditEntry(ctx context.Context, arg InsertAuditEntryParams) error {
	_, err := q.db.Exec(ctx, insertAuditEntry,
		arg.ActorType,
		arg.ActorID,
		arg.Action,
		arg.EntityID,
		arg.Method,
		arg.Path,
		arg.StatusCode,
		arg.Detail,
		arg.SourceIp,
		arg.CorrelationID,
		arg.SessionID,
	)
	return err
}

const insertCheckDef = `-- name: InsertCheckDef :exec
INSERT INTO check_defs (entity_id, target_id, target_type, kind, config, interval_s, timeout_s, zone, enabled)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
`

type InsertCheckDefParams struct {
	EntityID   uuid.UUID
	TargetID   *uuid.UUID
	TargetType *string
	Kind       string
	Config     []byte
	IntervalS  int32
	TimeoutS   int32
	Zone       *string
	Enabled    bool
}

func (q *Queries) InsertCheckDef(ctx context.Context, arg InsertCheckDefParams) error {
	_, err := q.db.Exec(ctx, insertCheckDef,
		arg.EntityID,
		arg.TargetID,
		arg.TargetType,
		arg.Kind,
		arg.Config,
		arg.IntervalS,
		arg.TimeoutS,
		arg.Zone,
		arg.Enabled,
	)
	return err
}

const insertEvent = `-- name: InsertEvent :one
INSERT INTO events (type, entity_id, severity, source, data, correlation_id)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, ts
`

type InsertEventParams struct {
	Type          string
	EntityID      *uuid.UUID
	Severity      string
	Source        string
	Data          []byte
	CorrelationID *string
}

type InsertEventRow struct {
	ID int64
	Ts time.Time
}

func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) (InsertEventRow, error) {
	row := q.db.QueryRow(ctx, insertEvent,
		arg.Type,
		arg.EntityID,
		arg.Severity,
		arg.Source,
		arg.Data,
		arg.CorrelationID,
	)
	var i InsertEventRow
	err := row.Scan(&i.ID, &i.Ts)
	return i, err
}

const insertExecution = `-- name: InsertExecution :exec
INSERT INTO executions (entity_id, classification_id, signal_entity_id,
    target_entity_id, action, risk_class, approval_id, agent_id,
    skill_id, skill_version, status, correlation_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'proposed', $11)
`

type InsertExecutionParams struct {
	EntityID         uuid.UUID
	ClassificationID *uuid.UUID
	SignalEntityID   *uuid.UUID
	TargetEntityID   *uuid.UUID
	Action           string
	RiskClass        string
	ApprovalID       *uuid.UUID
	AgentID          *uuid.UUID
	SkillID          *uuid.UUID
	SkillVersion     *int32
	CorrelationID    string
}

func (q *Queries) InsertExecution(ctx context.Context, arg InsertExecutionParams) error {
	_, err := q.db.Exec(ctx, insertExecution,
		arg.EntityID,
		arg.ClassificationID,
		arg.SignalEntityID,
		arg.TargetEntityID,
		arg.Action,
		arg.RiskClass,
		arg.ApprovalID,
		arg.AgentID,
		arg.SkillID,
		arg.SkillVersion,
		arg.CorrelationID,
	)
	return err
}

const insertMetricSample = `-- name: InsertMetricSample :exec
INSERT INTO metric_samples (entity_id, metric, value, tags, ts)
VALUES ($1, $2, $3, $4, now())
`

type InsertMetricSampleParams struct {
	EntityID uuid.UUID
	Metric   string
	Value    float64
	Tags     []byte
}

func (q *Queries) InsertMetricSample(ctx context.Context, arg InsertMetricSampleParams) error {
	_, err := q.db.Exec(ctx, insertMetricSample,
		arg.EntityID,
		arg.Metric,
		arg.Value,
		arg.Tags,
	)
	return err
}

const listApprovalRules = `-- name: ListApprovalRules :many
SELECT id, entity_type, action, risk_class, autonomy_level, scope_entity, version, updated_at FROM approval_rules ORDER BY entity_type, action
`

func (q *Queries) ListApprovalRules(ctx context.Context) ([]ApprovalRule, error) {
	rows, err := q.db.Query(ctx, listApprovalRules)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ApprovalRule
	for rows.Next() {
		var i ApprovalRule
		if err := rows.Scan(
			&i.ID,
			&i.EntityType,
			&i.Action,
			&i.RiskClass,
			&i.AutonomyLevel,
			&i.ScopeEntity,
			&i.Version,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listApprovals = `-- name: ListApprovals :many
SELECT a.entity_id, a.subject_entity_id, a.action, a.risk_class, a.kind, a.payload, a.status, a.token_hash, a.expires_at, a.decided_at, a.decided_by, a.created_at, a.matrix_event_id, a.alert_sent_at, e.slug AS subject_slug
FROM approvals a
JOIN entities e ON e.id = a.subject_entity_id
WHERE ($1::text IS NULL OR a.status = $1)
  AND ($2::text IS NULL OR e.slug > $2)
ORDER BY e.slug
LIMIT $3
`

type ListApprovalsParams struct {
	Status *string
	Cursor *string
	Lim    int32
}

type ListApprovalsRow struct {
	EntityID        uuid.UUID
	SubjectEntityID *uuid.UUID
	Action          string
	RiskClass       string
	Kind            string
	Payload         []byte
	Status          string
	TokenHash       *string
	ExpiresAt       time.Time
	DecidedAt       *time.Time
	DecidedBy       *uuid.UUID
	CreatedAt       time.Time
	MatrixEventID   *string
	AlertSentAt     *time.Time
	SubjectSlug     string
}

func (q *Queries) ListApprovals(ctx context.Context, arg ListApprovalsParams) ([]ListApprovalsRow, error) {
	rows, err := q.db.Query(ctx, listApprovals, arg.Status, arg.Cursor, arg.Lim)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListApprovalsRow
	for rows.Next() {
		var i ListApprovalsRow
		if err := rows.Scan(
			&i.EntityID,
			&i.SubjectEntityID,
			&i.Action,
			&i.RiskClass,
			&i.Kind,
			&i.Payload,
			&i.Status,
			&i.TokenHash,
			&i.ExpiresAt,
			&i.DecidedAt,
			&i.DecidedBy,
			&i.CreatedAt,
			&i.MatrixEventID,
			&i.AlertSentAt,
			&i.SubjectSlug,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listClassifications = `-- name: ListClassifications :many
SELECT c.entity_id, c.signal_entity_id, c.target_entity_id, c.action,
       c.recommended_action, c.risk_class, c.route, c.blast_radius,
       c.pattern_confidence, c.skill_id, c.autonomy_check, c.reasoning,
       c.correlation_id, c.created_at,
       e.slug AS target_slug
FROM classifications c
JOIN entities e ON e.id = c.target_entity_id
WHERE ($1::text IS NULL OR c.route = $1)
  AND ($2::text IS NULL OR e.slug > $2)
ORDER BY e.slug
LIMIT $3
`

type ListClassificationsParams struct {
	Route  *string
	Cursor *string
	Lim    int32
}

type ListClassificationsRow struct {
	EntityID          uuid.UUID
	SignalEntityID    *uuid.UUID
	TargetEntityID    *uuid.UUID
	Action            string
	RecommendedAction []byte
	RiskClass         string
	Route             string
	BlastRadius       []uuid.UUID
	PatternConfidence *float32
	SkillID           *uuid.UUID
	AutonomyCheck     *string
	Reasoning         []byte
	CorrelationID     string
	CreatedAt         time.Time
	TargetSlug        string
}

func (q *Queries) ListClassifications(ctx context.Context, arg ListClassificationsParams) ([]ListClassificationsRow, error) {
	rows, err := q.db.Query(ctx, listClassifications, arg.Route, arg.Cursor, arg.Lim)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListClassificationsRow
	for rows.Next() {
		var i ListClassificationsRow
		if err := rows.Scan(
			&i.EntityID,
			&i.SignalEntityID,
			&i.TargetEntityID,
			&i.Action,
			&i.RecommendedAction,
			&i.RiskClass,
			&i.Route,
			&i.BlastRadius,
			&i.PatternConfidence,
			&i.SkillID,
			&i.AutonomyCheck,
			&i.Reasoning,
			&i.CorrelationID,
			&i.CreatedAt,
			&i.TargetSlug,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listEnabledCheckDefs = `-- name: ListEnabledCheckDefs :many

SELECT cd.entity_id, cd.target_id, cd.target_type, cd.kind, cd.config,
       cd.interval_s, cd.timeout_s, cd.zone, cd.enabled, cd.updated_at,
       e.slug AS entity_slug
FROM check_defs cd
JOIN entities e ON e.id = cd.entity_id
LEFT JOIN entities tgt ON tgt.id = cd.target_id
WHERE cd.enabled = true
  AND (tgt.id IS NULL OR tgt.state IS NULL OR tgt.state NOT IN ('deprecated', 'destroyed'))
  AND (cd.last_run_at IS NULL
       OR cd.last_run_at <= now() - make_interval(secs => cd.interval_s))
`

type ListEnabledCheckDefsRow struct {
	EntityID   uuid.UUID
	TargetID   *uuid.UUID
	TargetType *string
	Kind       string
	Config     []byte
	IntervalS  int32
	TimeoutS   int32
	Zone       *string
	Enabled    bool
	UpdatedAt  time.Time
	EntitySlug string
}

// =====================================================================
// Phase 3 queries
// =====================================================================
// Enabled AND due. interval_s used to be selected but never filtered on, so
// every check ran on every 30s pass and the declared intervals meant nothing.
// NULL last_run_at = never run = due now.
func (q *Queries) ListEnabledCheckDefs(ctx context.Context) ([]ListEnabledCheckDefsRow, error) {
	rows, err := q.db.Query(ctx, listEnabledCheckDefs)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListEnabledCheckDefsRow
	for rows.Next() {
		var i ListEnabledCheckDefsRow
		if err := rows.Scan(
			&i.EntityID,
			&i.TargetID,
			&i.TargetType,
			&i.Kind,
			&i.Config,
			&i.IntervalS,
			&i.TimeoutS,
			&i.Zone,
			&i.Enabled,
			&i.UpdatedAt,
			&i.EntitySlug,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listEvents = `-- name: ListEvents :many
SELECT id, ts, type, entity_id, severity, source, data, correlation_id
FROM events
WHERE ($1::text IS NULL OR type = $1)
  AND ($2::uuid IS NULL OR entity_id = $2)
  AND ($3::text IS NULL OR severity = $3)
  AND ($4::text IS NULL OR correlation_id = $4)
  AND ($5::timestamptz IS NULL OR ts >= $5)
  AND ($6::timestamptz IS NULL OR ts <= $6)
  AND ($7::bigint IS NULL OR id < $7)
ORDER BY id DESC
LIMIT $8
`

type ListEventsParams struct {
	Type          *string
	EntityID      *uuid.UUID
	Severity      *string
	CorrelationID *string
	FromTs        *time.Time
	ToTs          *time.Time
	BeforeID      *int64
	Lim           int32
}

func (q *Queries) ListEvents(ctx context.Context, arg ListEventsParams) ([]Event, error) {
	rows, err := q.db.Query(ctx, listEvents,
		arg.Type,
		arg.EntityID,
		arg.Severity,
		arg.CorrelationID,
		arg.FromTs,
		arg.ToTs,
		arg.BeforeID,
		arg.Lim,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Event
	for rows.Next() {
		var i Event
		if err := rows.Scan(
			&i.ID,
			&i.Ts,
			&i.Type,
			&i.EntityID,
			&i.Severity,
			&i.Source,
			&i.Data,
			&i.CorrelationID,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listEventsAfter = `-- name: ListEventsAfter :many
SELECT id, ts, type, entity_id, severity, source, data, correlation_id
FROM events WHERE id > $1 ORDER BY id ASC LIMIT $2
`

type ListEventsAfterParams struct {
	ID    int64
	Limit int32
}

func (q *Queries) ListEventsAfter(ctx context.Context, arg ListEventsAfterParams) ([]Event, error) {
	rows, err := q.db.Query(ctx, listEventsAfter, arg.ID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Event
	for rows.Next() {
		var i Event
		if err := rows.Scan(
			&i.ID,
			&i.Ts,
			&i.Type,
			&i.EntityID,
			&i.Severity,
			&i.Source,
			&i.Data,
			&i.CorrelationID,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listExecutions = `-- name: ListExecutions :many
SELECT e.entity_id, e.classification_id, e.signal_entity_id, e.target_entity_id,
       e.action, e.risk_class, e.approval_id, e.agent_id,
       e.skill_id, e.skill_version, e.status, e.result, e.duration_ms,
       e.verified, e.correlation_id, e.started_at, e.completed_at, e.created_at,
       te.slug AS target_slug
FROM executions e
JOIN entities te ON te.id = e.target_entity_id
WHERE ($1::text IS NULL OR e.status = $1)
  AND ($2::text IS NULL OR te.slug > $2)
ORDER BY te.slug
LIMIT $3
`

type ListExecutionsParams struct {
	Status *string
	Cursor *string
	Lim    int32
}

type ListExecutionsRow struct {
	EntityID         uuid.UUID
	ClassificationID *uuid.UUID
	SignalEntityID   *uuid.UUID
	TargetEntityID   *uuid.UUID
	Action           string
	RiskClass        string
	ApprovalID       *uuid.UUID
	AgentID          *uuid.UUID
	SkillID          *uuid.UUID
	SkillVersion     *int32
	Status           string
	Result           []byte
	DurationMs       *int32
	Verified         bool
	CorrelationID    string
	StartedAt        *time.Time
	CompletedAt      *time.Time
	CreatedAt        time.Time
	TargetSlug       string
}

func (q *Queries) ListExecutions(ctx context.Context, arg ListExecutionsParams) ([]ListExecutionsRow, error) {
	rows, err := q.db.Query(ctx, listExecutions, arg.Status, arg.Cursor, arg.Lim)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListExecutionsRow
	for rows.Next() {
		var i ListExecutionsRow
		if err := rows.Scan(
			&i.EntityID,
			&i.ClassificationID,
			&i.SignalEntityID,
			&i.TargetEntityID,
			&i.Action,
			&i.RiskClass,
			&i.ApprovalID,
			&i.AgentID,
			&i.SkillID,
			&i.SkillVersion,
			&i.Status,
			&i.Result,
			&i.DurationMs,
			&i.Verified,
			&i.CorrelationID,
			&i.StartedAt,
			&i.CompletedAt,
			&i.CreatedAt,
			&i.TargetSlug,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listPatterns = `-- name: ListPatterns :many
SELECT p.entity_id, p.applies_type, p.action, p.pattern, p.confidence, p.evidence_count, p.success_count, p.failure_count, p.status, p.quarantined, p.version, p.last_validated_at, p.created_at FROM patterns p
WHERE ($1::text IS NULL OR p.status = $1)
ORDER BY p.applies_type, p.action
`

func (q *Queries) ListPatterns(ctx context.Context, status *string) ([]Pattern, error) {
	rows, err := q.db.Query(ctx, listPatterns, status)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Pattern
	for rows.Next() {
		var i Pattern
		if err := rows.Scan(
			&i.EntityID,
			&i.AppliesType,
			&i.Action,
			&i.Pattern,
			&i.Confidence,
			&i.EvidenceCount,
			&i.SuccessCount,
			&i.FailureCount,
			&i.Status,
			&i.Quarantined,
			&i.Version,
			&i.LastValidatedAt,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listRiskClasses = `-- name: ListRiskClasses :many
SELECT name, description, approval_required, autonomy_allowed FROM risk_classes ORDER BY name
`

func (q *Queries) ListRiskClasses(ctx context.Context) ([]RiskClass, error) {
	rows, err := q.db.Query(ctx, listRiskClasses)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []RiskClass
	for rows.Next() {
		var i RiskClass
		if err := rows.Scan(
			&i.Name,
			&i.Description,
			&i.ApprovalRequired,
			&i.AutonomyAllowed,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSignals = `-- name: ListSignals :many
SELECT sig.entity_id, se.slug, sig.kind, sig.severity, sig.state,
       te.slug AS target_slug, sig.check_id, sig.evidence, sig.likely_cause,
       sig.occurrence_count, sig.flap_count, sig.hold_down_until,
       sig.mute_until, sig.first_seen_at, sig.last_seen_at
FROM signals sig
JOIN entities se ON se.id = sig.entity_id
LEFT JOIN entities te ON te.id = sig.target_entity_id
WHERE ($1::text IS NULL OR sig.state = $1)
  AND ($2::text IS NULL OR sig.severity = $2)
  AND ($3::text IS NULL OR te.slug = $3)
  AND ($4::text IS NULL OR sig.kind = $4)
  AND ($5::text IS NULL OR se.slug > $5)
ORDER BY se.slug
LIMIT $6
`

type ListSignalsParams struct {
	State    *string
	Severity *string
	Target   *string
	Kind     *string
	Cursor   *string
	Lim      int32
}

type ListSignalsRow struct {
	EntityID        uuid.UUID
	Slug            string
	Kind            string
	Severity        string
	State           string
	TargetSlug      *string
	CheckID         *uuid.UUID
	Evidence        *string
	LikelyCause     *string
	OccurrenceCount int32
	FlapCount       int32
	HoldDownUntil   *time.Time
	MuteUntil       *time.Time
	FirstSeenAt     time.Time
	LastSeenAt      time.Time
}

func (q *Queries) ListSignals(ctx context.Context, arg ListSignalsParams) ([]ListSignalsRow, error) {
	rows, err := q.db.Query(ctx, listSignals,
		arg.State,
		arg.Severity,
		arg.Target,
		arg.Kind,
		arg.Cursor,
		arg.Lim,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ListSignalsRow
	for rows.Next() {
		var i ListSignalsRow
		if err := rows.Scan(
			&i.EntityID,
			&i.Slug,
			&i.Kind,
			&i.Severity,
			&i.State,
			&i.TargetSlug,
			&i.CheckID,
			&i.Evidence,
			&i.LikelyCause,
			&i.OccurrenceCount,
			&i.FlapCount,
			&i.HoldDownUntil,
			&i.MuteUntil,
			&i.FirstSeenAt,
			&i.LastSeenAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listSkills = `-- name: ListSkills :many
SELECT entity_id, version, name, procedure, applies_type, action, pattern_ids, status, success_rate, changed_by, change_reason, last_used_at, created_at FROM skills
WHERE ($1::text IS NULL OR status = $1)
ORDER BY name, version DESC
`

func (q *Queries) ListSkills(ctx context.Context, status *string) ([]Skill, error) {
	rows, err := q.db.Query(ctx, listSkills, status)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Skill
	for rows.Next() {
		var i Skill
		if err := rows.Scan(
			&i.EntityID,
			&i.Version,
			&i.Name,
			&i.Procedure,
			&i.AppliesType,
			&i.Action,
			&i.PatternIds,
			&i.Status,
			&i.SuccessRate,
			&i.ChangedBy,
			&i.ChangeReason,
			&i.LastUsedAt,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const markCheckRun = `-- name: MarkCheckRun :exec
UPDATE check_defs SET last_run_at = now(), last_health = $2 WHERE entity_id = $1
`

type MarkCheckRunParams struct {
	EntityID   uuid.UUID
	LastHealth *string
}

func (q *Queries) MarkCheckRun(ctx context.Context, arg MarkCheckRunParams) error {
	_, err := q.db.Exec(ctx, markCheckRun, arg.EntityID, arg.LastHealth)
	return err
}

const putIdempotentResponse = `-- name: PutIdempotentResponse :exec
INSERT INTO idempotency_keys (actor, key, request_hash, response_code, response_body)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (actor, key) DO NOTHING
`

type PutIdempotentResponseParams struct {
	Actor        string
	Key          string
	RequestHash  string
	ResponseCode *int32
	ResponseBody []byte
}

func (q *Queries) PutIdempotentResponse(ctx context.Context, arg PutIdempotentResponseParams) error {
	_, err := q.db.Exec(ctx, putIdempotentResponse,
		arg.Actor,
		arg.Key,
		arg.RequestHash,
		arg.ResponseCode,
		arg.ResponseBody,
	)
	return err
}

const queryMetrics = `-- name: QueryMetrics :many
SELECT time_bucket($4::interval, ts) AS bucket,
       entity_id, metric,
       ROUND(avg(value)::numeric, 2) AS avg_val,
       ROUND(min(value)::numeric, 2) AS min_val,
       ROUND(max(value)::numeric, 2) AS max_val
FROM metric_samples
WHERE entity_id = $1
  AND metric = $2
  AND ts > $3
GROUP BY bucket, entity_id, metric
ORDER BY bucket DESC
`

type QueryMetricsParams struct {
	EntityID       uuid.UUID
	Metric         string
	Ts             time.Time
	BucketInterval pgtype.Interval
}

type QueryMetricsRow struct {
	Bucket   interface{}
	EntityID uuid.UUID
	Metric   string
	AvgVal   pgtype.Numeric
	MinVal   pgtype.Numeric
	MaxVal   pgtype.Numeric
}

func (q *Queries) QueryMetrics(ctx context.Context, arg QueryMetricsParams) ([]QueryMetricsRow, error) {
	rows, err := q.db.Query(ctx, queryMetrics,
		arg.EntityID,
		arg.Metric,
		arg.Ts,
		arg.BucketInterval,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []QueryMetricsRow
	for rows.Next() {
		var i QueryMetricsRow
		if err := rows.Scan(
			&i.Bucket,
			&i.EntityID,
			&i.Metric,
			&i.AvgVal,
			&i.MinVal,
			&i.MaxVal,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const updateApprovalStatus = `-- name: UpdateApprovalStatus :exec
UPDATE approvals SET status = $2, decided_at = now(), decided_by = $3
WHERE entity_id = $1 AND status = 'pending'
`

type UpdateApprovalStatusParams struct {
	EntityID  uuid.UUID
	Status    string
	DecidedBy *uuid.UUID
}

func (q *Queries) UpdateApprovalStatus(ctx context.Context, arg UpdateApprovalStatusParams) error {
	_, err := q.db.Exec(ctx, updateApprovalStatus, arg.EntityID, arg.Status, arg.DecidedBy)
	return err
}

const updateCheckDef = `-- name: UpdateCheckDef :exec
UPDATE check_defs SET kind = $2, config = $3, interval_s = $4, timeout_s = $5,
    target_id = $6, target_type = $7, zone = $8, enabled = $9, updated_at = now()
WHERE entity_id = $1
`

type UpdateCheckDefParams struct {
	EntityID   uuid.UUID
	Kind       string
	Config     []byte
	IntervalS  int32
	TimeoutS   int32
	TargetID   *uuid.UUID
	TargetType *string
	Zone       *string
	Enabled    bool
}

func (q *Queries) UpdateCheckDef(ctx context.Context, arg UpdateCheckDefParams) error {
	_, err := q.db.Exec(ctx, updateCheckDef,
		arg.EntityID,
		arg.Kind,
		arg.Config,
		arg.IntervalS,
		arg.TimeoutS,
		arg.TargetID,
		arg.TargetType,
		arg.Zone,
		arg.Enabled,
	)
	return err
}

const updateExecutionStatus = `-- name: UpdateExecutionStatus :exec
UPDATE executions SET status = $2, result = $3, duration_ms = $4,
    verified = $5, started_at = COALESCE(started_at, now()),
    completed_at = CASE WHEN $2 IN ('completed','failed','cancelled') THEN now() ELSE completed_at END
WHERE entity_id = $1
`

type UpdateExecutionStatusParams struct {
	EntityID   uuid.UUID
	Status     string
	Result     []byte
	DurationMs *int32
	Verified   bool
}

func (q *Queries) UpdateExecutionStatus(ctx context.Context, arg UpdateExecutionStatusParams) error {
	_, err := q.db.Exec(ctx, updateExecutionStatus,
		arg.EntityID,
		arg.Status,
		arg.Result,
		arg.DurationMs,
		arg.Verified,
	)
	return err
}

const updatePatternQuarantine = `-- name: UpdatePatternQuarantine :exec
UPDATE patterns SET quarantined = $2 WHERE entity_id = $1
`

type UpdatePatternQuarantineParams struct {
	EntityID    uuid.UUID
	Quarantined bool
}

func (q *Queries) UpdatePatternQuarantine(ctx context.Context, arg UpdatePatternQuarantineParams) error {
	_, err := q.db.Exec(ctx, updatePatternQuarantine, arg.EntityID, arg.Quarantined)
	return err
}

const updatePatternStatus = `-- name: UpdatePatternStatus :exec
UPDATE patterns SET status = $2, version = version + 1,
    last_validated_at = CASE WHEN $2 = 'validated' THEN now() ELSE last_validated_at END
WHERE entity_id = $1
`

type UpdatePatternStatusParams struct {
	EntityID uuid.UUID
	Status   string
}

func (q *Queries) UpdatePatternStatus(ctx context.Context, arg UpdatePatternStatusParams) error {
	_, err := q.db.Exec(ctx, updatePatternStatus, arg.EntityID, arg.Status)
	return err
}

const updateSkillStatus = `-- name: UpdateSkillStatus :exec
UPDATE skills SET status = $2, last_used_at = now() WHERE entity_id = $1 AND version = $2
`

type UpdateSkillStatusParams struct {
	EntityID uuid.UUID
	Status   string
}

func (q *Queries) UpdateSkillStatus(ctx context.Context, arg UpdateSkillStatusParams) error {
	_, err := q.db.Exec(ctx, updateSkillStatus, arg.EntityID, arg.Status)
	return err
}

const upsertEntityStatus = `-- name: UpsertEntityStatus :exec
INSERT INTO entity_status (entity_id, health, last_check_at, details)
VALUES ($1, $2, $3, $4)
ON CONFLICT (entity_id)
DO UPDATE SET health = EXCLUDED.health,
    last_check_at = EXCLUDED.last_check_at,
    details = EXCLUDED.details,
    updated_at = now()
`

type UpsertEntityStatusParams struct {
	EntityID    uuid.UUID
	Health      string
	LastCheckAt *time.Time
	Details     []byte
}

func (q *Queries) UpsertEntityStatus(ctx context.Context, arg UpsertEntityStatusParams) error {
	_, err := q.db.Exec(ctx, upsertEntityStatus,
		arg.EntityID,
		arg.Health,
		arg.LastCheckAt,
		arg.Details,
	)
	return err
}

const upsertPattern = `-- name: UpsertPattern :exec
INSERT INTO patterns (entity_id, applies_type, action, pattern, confidence,
    evidence_count, success_count, failure_count, status, version)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'hypothesized', 1)
ON CONFLICT (applies_type, action)
DO UPDATE SET evidence_count = patterns.evidence_count + EXCLUDED.evidence_count,
    success_count = patterns.success_count + EXCLUDED.success_count,
    failure_count = patterns.failure_count + EXCLUDED.failure_count,
    updated_at = now()
`

type UpsertPatternParams struct {
	EntityID      uuid.UUID
	AppliesType   string
	Action        string
	Pattern       string
	Confidence    float32
	EvidenceCount int32
	SuccessCount  int32
	FailureCount  int32
}

func (q *Queries) UpsertPattern(ctx context.Context, arg UpsertPatternParams) error {
	_, err := q.db.Exec(ctx, upsertPattern,
		arg.EntityID,
		arg.AppliesType,
		arg.Action,
		arg.Pattern,
		arg.Confidence,
		arg.EvidenceCount,
		arg.SuccessCount,
		arg.FailureCount,
	)
	return err
}

const upsertSignal = `-- name: UpsertSignal :one
INSERT INTO signals (entity_id, kind, severity, target_entity_id, check_id, evidence, likely_cause, state)
VALUES ($1, $2, $3, $4, $5, $6, $7, 'raised')
ON CONFLICT (target_entity_id, kind) WHERE state NOT IN ('resolved','failed')
DO UPDATE SET occurrence_count = signals.occurrence_count + 1,
              last_seen_at = now(),
              evidence = EXCLUDED.evidence,
              updated_at = now()
RETURNING entity_id, kind, severity, target_entity_id, check_id, evidence, likely_cause, state, occurrence_count, first_seen_at, last_seen_at, flap_count, hold_down_until, mute_until, created_at, updated_at
`

type UpsertSignalParams struct {
	EntityID       uuid.UUID
	Kind           string
	Severity       string
	TargetEntityID *uuid.UUID
	CheckID        *uuid.UUID
	Evidence       *string
	LikelyCause    *string
}

func (q *Queries) UpsertSignal(ctx context.Context, arg UpsertSignalParams) (Signal, error) {
	row := q.db.QueryRow(ctx, upsertSignal,
		arg.EntityID,
		arg.Kind,
		arg.Severity,
		arg.TargetEntityID,
		arg.CheckID,
		arg.Evidence,
		arg.LikelyCause,
	)
	var i Signal
	err := row.Scan(
		&i.EntityID,
		&i.Kind,
		&i.Severity,
		&i.TargetEntityID,
		&i.CheckID,
		&i.Evidence,
		&i.LikelyCause,
		&i.State,
		&i.OccurrenceCount,
		&i.FirstSeenAt,
		&i.LastSeenAt,
		&i.FlapCount,
		&i.HoldDownUntil,
		&i.MuteUntil,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const worstHealthForTarget = `-- name: WorstHealthForTarget :one
SELECT COALESCE(
  (SELECT last_health FROM check_defs
   WHERE enabled AND target_id = $1 AND last_health IS NOT NULL
   ORDER BY CASE last_health
     WHEN 'down' THEN 0 WHEN 'degraded' THEN 1 WHEN 'stale' THEN 2
     WHEN 'unknown' THEN 3 ELSE 4 END
   LIMIT 1),
  'unknown')::text AS health
`

// An entity is as healthy as its unhealthiest check. Checks that have not run
// yet (last_health IS NULL) are ignored rather than counted as unknown, so a
// newly added check does not drag a known-good entity down before it has
// produced a verdict.
func (q *Queries) WorstHealthForTarget(ctx context.Context, targetID *uuid.UUID) (string, error) {
	row := q.db.QueryRow(ctx, worstHealthForTarget, targetID)
	var health string
	err := row.Scan(&health)
	return health, err
}
