package store

import (
	"context"
	"fmt"
	"time"

	"github.com/jackc/pgx/v5"
)

// CaptionlessChannels returns the set of channel ids currently suppressed for the
// user — channels whose recent videos all yielded no captions, within their
// suppression window (ADR-024). The runner skips caption fetches for these
// channels' videos. A channel whose window has expired is not returned, so its
// next video is re-probed (auto-recovery).
func (s *Store) CaptionlessChannels(ctx context.Context, userID string) (map[string]bool, error) {
	out := map[string]bool{}
	err := s.withUser(ctx, userID, func(tx pgx.Tx) error {
		rows, err := tx.Query(ctx, `
			SELECT channel_id FROM channel_caption_state
			WHERE user_id = $1 AND captionless_until IS NOT NULL AND captionless_until > now()`,
			userID)
		if err != nil {
			return fmt.Errorf("store: caption-less channels: %w", err)
		}
		defer rows.Close()
		for rows.Next() {
			var ch string
			if err := rows.Scan(&ch); err != nil {
				return fmt.Errorf("store: scan caption-less channel: %w", err)
			}
			out[ch] = true
		}
		return rows.Err()
	})
	return out, err
}

// RecordChannelCaptionOutcome updates a channel's caption-availability memory
// after a fetch attempt (ADR-024). hadCaptions resets the channel (consecutive
// count to 0, suppression cleared). Otherwise the consecutive no-caption count is
// incremented; once it reaches threshold the channel is suppressed for window.
// threshold <= 0 is a no-op (feature disabled). An empty channelID is ignored
// (some sources may not carry one).
func (s *Store) RecordChannelCaptionOutcome(ctx context.Context, userID, channelID string, hadCaptions bool, threshold int, window time.Duration) error {
	if channelID == "" || threshold <= 0 {
		return nil
	}
	return s.withUser(ctx, userID, func(tx pgx.Tx) error {
		if hadCaptions {
			_, err := tx.Exec(ctx, `
				INSERT INTO channel_caption_state (user_id, channel_id, consecutive_none, captionless_until, updated_at)
				VALUES ($1, $2, 0, NULL, now())
				ON CONFLICT (user_id, channel_id)
				DO UPDATE SET consecutive_none = 0, captionless_until = NULL, updated_at = now()`,
				userID, channelID)
			if err != nil {
				return fmt.Errorf("store: reset channel caption state: %w", err)
			}
			return nil
		}
		// No captions: increment the streak; suppress once it reaches threshold.
		// captionless_until is set from the NEW count inside the same statement so
		// the decision is atomic with the increment.
		until := time.Now().Add(window)
		_, err := tx.Exec(ctx, `
			INSERT INTO channel_caption_state (user_id, channel_id, consecutive_none, captionless_until, updated_at)
			VALUES ($1, $2, 1, CASE WHEN 1 >= $3 THEN $4::timestamptz ELSE NULL END, now())
			ON CONFLICT (user_id, channel_id)
			DO UPDATE SET
				consecutive_none = channel_caption_state.consecutive_none + 1,
				captionless_until = CASE
					WHEN channel_caption_state.consecutive_none + 1 >= $3 THEN $4::timestamptz
					ELSE channel_caption_state.captionless_until
				END,
				updated_at = now()`,
			userID, channelID, threshold, until)
		if err != nil {
			return fmt.Errorf("store: record channel no-caption: %w", err)
		}
		return nil
	})
}
