package alert

import (
	"context"
	"fmt"
	"time"

	"github.com/jmoiron/sqlx"
)

// IDGenerator generates classification-neutral alert IDs such as ALT-2607-42.
type IDGenerator struct {
	db *sqlx.DB
}

func NewIDGenerator(db *sqlx.DB) *IDGenerator {
	return &IDGenerator{db: db}
}

// NextID returns the next alert ID for the given classification.
// LAST_INSERT_ID(expr) captures the incremented value on this connection, so
// concurrent increments can't read each other's sequence value. Both
// statements run in one transaction to guarantee they share a connection.
func (g *IDGenerator) NextID(ctx context.Context, classification string) (string, error) {
	prefix, err := g.prefix(classification)
	if err != nil {
		return "", err
	}

	tx, err := g.db.BeginTxx(ctx, nil)
	if err != nil {
		return "", fmt.Errorf("begin id seq tx: %w", err)
	}
	defer tx.Rollback()

	const q = `
		INSERT INTO alert_id_seq (prefix, next_val) VALUES (?, LAST_INSERT_ID(1))
		ON DUPLICATE KEY UPDATE next_val = LAST_INSERT_ID(next_val + 1)
	`
	if _, err := tx.ExecContext(ctx, q, prefix); err != nil {
		return "", fmt.Errorf("increment id seq: %w", err)
	}

	var seq uint64
	if err := tx.GetContext(ctx, &seq, `SELECT LAST_INSERT_ID()`); err != nil {
		return "", fmt.Errorf("get id seq: %w", err)
	}

	if err := tx.Commit(); err != nil {
		return "", fmt.Errorf("commit id seq: %w", err)
	}

	return fmt.Sprintf("%s-%d", prefix, seq), nil
}

func (g *IDGenerator) prefix(classification string) (string, error) {
	// UTC so the monthly rollover doesn't depend on container timezone.
	return alertIDPrefix(classification, time.Now().UTC())
}

func alertIDPrefix(classification string, now time.Time) (string, error) {
	switch classification {
	case ClassPage, ClassTicket:
		// Go reference: Jan 2006 → "0601" gives YYMM.
		return fmt.Sprintf("ALT-%s", now.UTC().Format("0601")), nil
	default:
		return "", fmt.Errorf("invalid classification for alert: %s", classification)
	}
}
