package postgres

import (
	"context"
	"fmt"
	"time"
)

type Card struct {
	ID                          string
	PublicID                    string
	CardType                    string
	Title                       string
	Subtitle                    *string
	CoverURL                    *string
	DisplaySlot                 string
	DisplayPriority             int
	IsDefaultExperience         bool
	StartsAt                    *time.Time
	EndsAt                      *time.Time
	EntryChannelID              *string
	EventPublicID               *string
	EventDisplayName            *string
	EventSummary                *string
	EventStatus                 *string
	EventCurrentReleasePubID    *string
	EventConfigLabel            *string
	EventRouteCode              *string
	EventReleasePayloadJSON     *string
	EventRuntimeBindingID       *string
	EventPresentationID         *string
	EventPresentationName       *string
	EventPresentationType       *string
	EventPresentationSchemaJSON *string
	EventContentBundleID        *string
	EventContentBundleName      *string
	EventContentEntryURL        *string
	EventContentAssetRootURL    *string
	EventContentMetadataJSON    *string
	HTMLURL                     *string
}

func (s *Store) ListCardsForEntry(ctx context.Context, tenantID string, entryChannelID *string, slot string, now time.Time, limit int) ([]Card, error) {
	if limit <= 0 || limit > 100 {
		limit = 20
	}
	if slot == "" {
		slot = "home_primary"
	}

	rows, err := s.pool.Query(ctx, `
		SELECT
			c.id,
			c.card_public_id,
			c.card_type,
			c.title,
			c.subtitle,
			c.cover_url,
			c.display_slot,
			c.display_priority,
			c.is_default_experience,
			c.starts_at,
			c.ends_at,
			c.entry_channel_id,
			e.event_public_id,
			e.display_name,
			e.summary,
			e.status,
			er.release_public_id,
			er.config_label,
			er.route_code,
			er.payload_jsonb::text,
			mrb.runtime_binding_public_id,
			ep.presentation_public_id,
			ep.name,
			ep.presentation_type,
			ep.schema_jsonb::text,
			cb.content_bundle_public_id,
			cb.name,
			cb.entry_url,
			cb.asset_root_url,
			cb.metadata_jsonb::text,
			c.html_url
		FROM cards c
		LEFT JOIN events e ON e.id = c.event_id
		LEFT JOIN event_releases er ON er.id = e.current_release_id
		LEFT JOIN map_runtime_bindings mrb ON mrb.id = er.runtime_binding_id
		LEFT JOIN event_presentations ep ON ep.id = er.presentation_id
		LEFT JOIN content_bundles cb ON cb.id = er.content_bundle_id
		WHERE c.tenant_id = $1
		  AND ($2::uuid IS NULL OR c.entry_channel_id = $2 OR c.entry_channel_id IS NULL)
		  AND c.display_slot = $3
		  AND c.status = 'active'
		  AND (c.starts_at IS NULL OR c.starts_at <= $4)
		  AND (c.ends_at IS NULL OR c.ends_at >= $4)
		ORDER BY
		  CASE WHEN $2::uuid IS NOT NULL AND c.entry_channel_id = $2 THEN 0 ELSE 1 END,
		  c.display_priority DESC,
		  c.created_at ASC
		LIMIT $5
	`, tenantID, entryChannelID, slot, now, limit)
	if err != nil {
		return nil, fmt.Errorf("list cards for entry: %w", err)
	}
	defer rows.Close()

	var cards []Card
	for rows.Next() {
		var card Card
		if err := rows.Scan(
			&card.ID,
			&card.PublicID,
			&card.CardType,
			&card.Title,
			&card.Subtitle,
			&card.CoverURL,
			&card.DisplaySlot,
			&card.DisplayPriority,
			&card.IsDefaultExperience,
			&card.StartsAt,
			&card.EndsAt,
			&card.EntryChannelID,
			&card.EventPublicID,
			&card.EventDisplayName,
			&card.EventSummary,
			&card.EventStatus,
			&card.EventCurrentReleasePubID,
			&card.EventConfigLabel,
			&card.EventRouteCode,
			&card.EventReleasePayloadJSON,
			&card.EventRuntimeBindingID,
			&card.EventPresentationID,
			&card.EventPresentationName,
			&card.EventPresentationType,
			&card.EventPresentationSchemaJSON,
			&card.EventContentBundleID,
			&card.EventContentBundleName,
			&card.EventContentEntryURL,
			&card.EventContentAssetRootURL,
			&card.EventContentMetadataJSON,
			&card.HTMLURL,
		); err != nil {
			return nil, fmt.Errorf("scan card: %w", err)
		}
		cards = append(cards, card)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate cards: %w", err)
	}
	return cards, nil
}
