package httpapi

import (
	"context"
	"encoding/json"

	"github.com/dtoro/oikos/internal/httpapi/gen"
)

func (s *Server) QueryAudit(ctx context.Context, req gen.QueryAuditRequestObject) (gen.QueryAuditResponseObject, error) {
	limit := clampLimit(req.Params.Limit)
	var actorType, actorID, action, entityID, correlationID *string
	if req.Params.ActorType != nil {
		actorType = req.Params.ActorType
	}
	if req.Params.ActorId != nil {
		actorID = req.Params.ActorId
	}
	if req.Params.Action != nil {
		action = req.Params.Action
	}
	if req.Params.EntityId != nil {
		entityID = req.Params.EntityId
	}
	if req.Params.CorrelationId != nil {
		correlationID = req.Params.CorrelationId
	}

	rows, err := s.pool.Query(ctx, `
		SELECT id, ts, actor_type, actor_id::text, action, entity_id::text,
		       method, path, status_code, detail, source_ip, correlation_id, session_id::text
		FROM audit_log
		WHERE ($1::text IS NULL OR actor_type = $1)
		  AND ($2::text IS NULL OR actor_id::text = $2)
		  AND ($3::text IS NULL OR action = $3)
		  AND ($4::text IS NULL OR entity_id::text = $4)
		  AND ($5::text IS NULL OR correlation_id = $5)
		  AND ($6::timestamptz IS NULL OR ts >= $6)
		  AND ($7::timestamptz IS NULL OR ts <= $7)
		ORDER BY ts DESC
		LIMIT $8`,
		actorType, actorID, action, entityID, correlationID, req.Params.From, req.Params.To, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	items := []gen.AuditEntry{}
	for rows.Next() {
		var a gen.AuditEntry
		var detailBytes []byte
		var actID, entID, method, path, sourceIP, corrID, sessionID *string
		var statusCode *int
		if err := rows.Scan(&a.Id, &a.Ts, &a.ActorType, &actID, &a.Action, &entID,
			&method, &path, &statusCode, &detailBytes, &sourceIP, &corrID, &sessionID); err != nil {
			return nil, err
		}
		a.ActorId = actID
		a.EntityId = entID
		a.Method = method
		a.Path = path
		a.StatusCode = statusCode
		a.SourceIp = sourceIP
		a.CorrelationId = corrID
		var detail map[string]any
		if json.Unmarshal(detailBytes, &detail) == nil {
			a.Detail = &detail
		}
		items = append(items, a)
	}
	return gen.QueryAudit200JSONResponse{Items: items}, rows.Err()
}