// alerts_read.go executes alert-run, alerts, and reference queries.
// Layer: adapters/outbound/postgres alerts feature.
package postgres

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	"gitea.maximumdirect.net/ejr/weatherfeeder/model"
)

func (r *Repository) LatestAlertRun(ctx context.Context) (*model.WeatherAlertRun, error) {
	if r == nil || r.db == nil {
		return nil, fmt.Errorf("postgres repository is not configured")
	}

	var row alertRunParentRow
	err := r.db.QueryRowContext(ctx, queryLatestAlertRun).Scan(
		&row.EventID,
		&row.LocationID,
		&row.LocationName,
		&row.AsOf,
		&row.Latitude,
		&row.Longitude,
	)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("query latest alert run: %w", err)
	}

	run := mapAlertRunParentRow(row)

	alerts, err := r.loadAlerts(ctx, row.EventID)
	if err != nil {
		return nil, err
	}
	run.Alerts = alerts

	return &run, nil
}

func (r *Repository) loadAlerts(ctx context.Context, eventID string) ([]model.WeatherAlert, error) {
	alertsRows, err := r.db.QueryContext(ctx, queryAlerts, eventID)
	if err != nil {
		return nil, fmt.Errorf("query alerts: %w", err)
	}
	defer alertsRows.Close()

	indexedAlerts := make([]indexedAlert, 0)
	for alertsRows.Next() {
		var row alertRow
		if err := alertsRows.Scan(
			&row.AlertIndex,
			&row.AlertID,
			&row.Event,
			&row.Headline,
			&row.Severity,
			&row.Urgency,
			&row.Certainty,
			&row.Status,
			&row.MessageType,
			&row.Category,
			&row.Response,
			&row.Description,
			&row.Instruction,
			&row.Sent,
			&row.Effective,
			&row.Onset,
			&row.Expires,
			&row.AreaDescription,
			&row.SenderName,
		); err != nil {
			return nil, fmt.Errorf("scan alerts row: %w", err)
		}
		indexedAlerts = append(indexedAlerts, mapAlertRow(row))
	}
	if err := alertsRows.Err(); err != nil {
		return nil, fmt.Errorf("iterate alerts rows: %w", err)
	}

	referenceRows, err := r.db.QueryContext(ctx, queryAlertReferences, eventID)
	if err != nil {
		return nil, fmt.Errorf("query alert references: %w", err)
	}
	defer referenceRows.Close()

	indexedReferences := make([]indexedAlertReference, 0)
	for referenceRows.Next() {
		var row alertReferenceRow
		if err := referenceRows.Scan(
			&row.AlertIndex,
			&row.ID,
			&row.Identifier,
			&row.Sender,
			&row.Sent,
		); err != nil {
			return nil, fmt.Errorf("scan alert reference row: %w", err)
		}
		indexedReferences = append(indexedReferences, mapAlertReferenceRow(row))
	}
	if err := referenceRows.Err(); err != nil {
		return nil, fmt.Errorf("iterate alert reference rows: %w", err)
	}

	return attachAlertReferences(indexedAlerts, indexedReferences), nil
}
