// Package dlq is the M8 dead-letter queue writer used by
// deliverd-fcm and deliverd-telegram. When a delivery
// exhausts its retry budget, the worker calls Write()
// once to insert a forensic row into deliveries_dlq and
// mark the live deliveries row as status='dlq'.
//
// The package is intentionally tiny: one function, one
// row insert, one row update. The retry loop itself
// stays in the deliverd main.go (it's small and per-
// channel, since the HTTP target and the request shape
// differ per channel).
//
// Schema reference: migrations/008_dlq.up.sql.
package dlq

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

	"git3.techno-world.net/lrosales/broad-announce/internal/postgres"
)

// Entry is the minimal payload we need to write a DLQ
// row. It mirrors the columns of `deliveries_dlq` that
// the worker fills in; everything else (id, created_at,
// discarded) is set by the database.
type Entry struct {
	AlertID         string
	CompanyID       string
	IndividualID    string
	Channel         string // fcm | telegram | …
	Target          string // fcm_token, chat_id, …
	OriginalSubject string // deliveries.fcm.<co>, for replay
	Attempts        int
	LastError       string
	Payload         json.RawMessage // raw NATS envelope bytes
}

// Write inserts one row into deliveries_dlq. It does
// NOT touch the per-attempt `deliveries` rows — those
// are the audit trail of what each attempt saw (status
// 'failed' or 'sent'), and we keep them as-is so the
// operator can see "this alert had N attempts and all
// failed" at a glance. The DLQ row is the source of
// truth for "this alert hit the DLQ" and the gateway
// for replay.
//
// Returns the new DLQ row's id (for logging).
func Write(ctx context.Context, pool *postgres.Pool, e Entry) (int64, error) {
	if e.OriginalSubject == "" {
		return 0, fmt.Errorf("dlq.Write: OriginalSubject is required for replay")
	}
	if e.Payload == nil {
		// Store the literal JSON null rather than an
		// empty byte slice so CH's String column gets
		// a sensible value.
		e.Payload = json.RawMessage("null")
	}
	// The DLQ insert.
	var newID int64
	err := pool.QueryRow(ctx, `
		INSERT INTO deliveries_dlq
		    (alert_id, company_id, individual_id, channel, target,
		     original_subject, attempts, last_error, payload)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
		RETURNING id
	`,
		e.AlertID, e.CompanyID, e.IndividualID, e.Channel, e.Target,
		e.OriginalSubject, e.Attempts, e.LastError, e.Payload,
	).Scan(&newID)
	if err != nil {
		return 0, fmt.Errorf("dlq insert: %w", err)
	}

	return newID, nil
}
