package service

import (
	"context"
	"net/http"
	"strings"
	"time"

	"cmr-backend/internal/apperr"
	"cmr-backend/internal/store/postgres"
)

type HomeService struct {
	store *postgres.Store
}

type ListCardsInput struct {
	ChannelCode   string
	ChannelType   string
	PlatformAppID string
	TenantCode    string
	Slot          string
	Limit         int
}

type CardResult struct {
	ID                   string                    `json:"id"`
	Type                 string                    `json:"type"`
	Title                string                    `json:"title"`
	Subtitle             *string                   `json:"subtitle,omitempty"`
	Summary              *string                   `json:"summary,omitempty"`
	CoverURL             *string                   `json:"coverUrl,omitempty"`
	DisplaySlot          string                    `json:"displaySlot"`
	DisplayPriority      int                       `json:"displayPriority"`
	Status               string                    `json:"status"`
	StatusCode           string                    `json:"statusCode"`
	TimeWindow           string                    `json:"timeWindow"`
	CTAText              string                    `json:"ctaText"`
	IsDefaultExperience  bool                      `json:"isDefaultExperience"`
	EventType            *string                   `json:"eventType,omitempty"`
	CurrentPresentation  *PresentationSummaryView  `json:"currentPresentation,omitempty"`
	CurrentContentBundle *ContentBundleSummaryView `json:"currentContentBundle,omitempty"`
	Event                *struct {
		ID          string  `json:"id"`
		DisplayName string  `json:"displayName"`
		Summary     *string `json:"summary,omitempty"`
		Status      *string `json:"status,omitempty"`
	} `json:"event,omitempty"`
	HTMLURL *string `json:"htmlUrl,omitempty"`
}

type HomeResult struct {
	Tenant struct {
		ID   string `json:"id"`
		Code string `json:"code"`
		Name string `json:"name"`
	} `json:"tenant"`
	Channel struct {
		ID            string  `json:"id"`
		Code          string  `json:"code"`
		Type          string  `json:"type"`
		PlatformAppID *string `json:"platformAppId,omitempty"`
		DisplayName   string  `json:"displayName"`
		Status        string  `json:"status"`
		IsDefault     bool    `json:"isDefault"`
	} `json:"channel"`
	Cards []CardResult `json:"cards"`
}

func NewHomeService(store *postgres.Store) *HomeService {
	return &HomeService{store: store}
}

func (s *HomeService) ListCards(ctx context.Context, input ListCardsInput) ([]CardResult, error) {
	entry, err := s.resolveEntry(ctx, input)
	if err != nil {
		return nil, err
	}

	cards, err := s.store.ListCardsForEntry(ctx, entry.TenantID, &entry.ID, normalizeSlot(input.Slot), time.Now().UTC(), input.Limit)
	if err != nil {
		return nil, err
	}
	return mapCards(cards), nil
}

func (s *HomeService) GetHome(ctx context.Context, input ListCardsInput) (*HomeResult, error) {
	entry, err := s.resolveEntry(ctx, input)
	if err != nil {
		return nil, err
	}

	cards, err := s.store.ListCardsForEntry(ctx, entry.TenantID, &entry.ID, normalizeSlot(input.Slot), time.Now().UTC(), input.Limit)
	if err != nil {
		return nil, err
	}

	result := &HomeResult{
		Cards: mapCards(cards),
	}
	result.Tenant.ID = entry.TenantID
	result.Tenant.Code = entry.TenantCode
	result.Tenant.Name = entry.TenantName
	result.Channel.ID = entry.ID
	result.Channel.Code = entry.ChannelCode
	result.Channel.Type = entry.ChannelType
	result.Channel.PlatformAppID = entry.PlatformAppID
	result.Channel.DisplayName = entry.DisplayName
	result.Channel.Status = entry.Status
	result.Channel.IsDefault = entry.IsDefault
	return result, nil
}

func (s *HomeService) resolveEntry(ctx context.Context, input ListCardsInput) (*postgres.EntryChannel, error) {
	entry, err := s.store.FindEntryChannel(ctx, postgres.FindEntryChannelParams{
		ChannelCode:   strings.TrimSpace(input.ChannelCode),
		ChannelType:   strings.TrimSpace(input.ChannelType),
		PlatformAppID: strings.TrimSpace(input.PlatformAppID),
		TenantCode:    strings.TrimSpace(input.TenantCode),
	})
	if err != nil {
		return nil, err
	}
	if entry == nil {
		return nil, apperr.New(http.StatusNotFound, "entry_channel_not_found", "entry channel not found")
	}
	return entry, nil
}

func normalizeSlot(slot string) string {
	slot = strings.TrimSpace(slot)
	if slot == "" {
		return "home_primary"
	}
	return slot
}

func mapCards(cards []postgres.Card) []CardResult {
	results := make([]CardResult, 0, len(cards))
	for _, card := range cards {
		statusCode, statusText := deriveCardStatus(card)
		item := CardResult{
			ID:                   card.PublicID,
			Type:                 card.CardType,
			Title:                fallbackCardTitle(card.Title),
			Subtitle:             card.Subtitle,
			Summary:              fallbackCardSummary(card.EventSummary),
			CoverURL:             card.CoverURL,
			DisplaySlot:          card.DisplaySlot,
			DisplayPriority:      card.DisplayPriority,
			Status:               statusText,
			StatusCode:           statusCode,
			TimeWindow:           deriveCardTimeWindow(card),
			CTAText:              deriveCardCTAText(card, statusCode),
			IsDefaultExperience:  card.IsDefaultExperience,
			EventType:            deriveCardEventType(card),
			CurrentPresentation:  buildCardPresentationSummary(card),
			CurrentContentBundle: buildCardContentBundleSummary(card),
			HTMLURL:              card.HTMLURL,
		}
		if card.EventPublicID != nil || card.EventDisplayName != nil {
			item.Event = &struct {
				ID          string  `json:"id"`
				DisplayName string  `json:"displayName"`
				Summary     *string `json:"summary,omitempty"`
				Status      *string `json:"status,omitempty"`
			}{
				Summary: card.EventSummary,
				Status:  card.EventStatus,
			}
			if card.EventPublicID != nil {
				item.Event.ID = *card.EventPublicID
			}
			if card.EventDisplayName != nil {
				item.Event.DisplayName = *card.EventDisplayName
			}
		}
		results = append(results, item)
	}
	return results
}

func fallbackCardTitle(title string) string {
	title = strings.TrimSpace(title)
	if title == "" {
		return "未命名活动"
	}
	return title
}

func fallbackCardSummary(summary *string) *string {
	if summary != nil && strings.TrimSpace(*summary) != "" {
		return summary
	}
	text := "当前暂无活动摘要"
	return &text
}

func deriveCardStatus(card postgres.Card) (string, string) {
	if card.EventStatus == nil {
		return "pending", "状态待确认"
	}
	switch strings.TrimSpace(*card.EventStatus) {
	case "active":
		if card.EventCurrentReleasePubID == nil {
			return "upcoming", "即将开始"
		}
		if card.EventRuntimeBindingID == nil || card.EventPresentationID == nil || card.EventContentBundleID == nil {
			return "upcoming", "即将开始"
		}
		return "running", "进行中"
	case "archived", "disabled", "inactive":
		return "ended", "已结束"
	default:
		return "pending", "状态待确认"
	}
}

func deriveCardTimeWindow(card postgres.Card) string {
	if card.StartsAt == nil && card.EndsAt == nil {
		return "时间待公布"
	}
	const layout = "01-02 15:04"
	switch {
	case card.StartsAt != nil && card.EndsAt != nil:
		return card.StartsAt.Local().Format(layout) + " - " + card.EndsAt.Local().Format(layout)
	case card.StartsAt != nil:
		return "开始于 " + card.StartsAt.Local().Format(layout)
	default:
		return "截止至 " + card.EndsAt.Local().Format(layout)
	}
}

func deriveCardCTAText(card postgres.Card, statusCode string) string {
	if card.IsDefaultExperience {
		return "进入体验"
	}
	switch statusCode {
	case "running":
		return "进入活动"
	case "ended":
		return "查看回顾"
	default:
		return "查看详情"
	}
}

func deriveCardEventType(card postgres.Card) *string {
	if card.EventReleasePayloadJSON != nil {
		payload, err := decodeJSONObject(*card.EventReleasePayloadJSON)
		if err == nil {
			if game, ok := payload["game"].(map[string]any); ok {
				if rawMode, ok := game["mode"].(string); ok {
					switch strings.TrimSpace(rawMode) {
					case "classic-sequential":
						text := "顺序赛"
						return &text
					case "score-o":
						text := "积分赛"
						return &text
					}
				}
			}
			if plan := resolveVariantPlan(card.EventReleasePayloadJSON); plan.AssignmentMode != nil && *plan.AssignmentMode == AssignmentModeManual {
				text := "多赛道"
				return &text
			}
		}
	}
	if card.IsDefaultExperience {
		text := "体验活动"
		return &text
	}
	return nil
}

func buildCardPresentationSummary(card postgres.Card) *PresentationSummaryView {
	if card.EventPresentationID == nil {
		return nil
	}
	summary := &PresentationSummaryView{
		PresentationID:   *card.EventPresentationID,
		Name:             card.EventPresentationName,
		PresentationType: card.EventPresentationType,
	}
	if card.EventPresentationSchemaJSON != nil && strings.TrimSpace(*card.EventPresentationSchemaJSON) != "" {
		if schema, err := decodeJSONObject(*card.EventPresentationSchemaJSON); err == nil {
			summary.TemplateKey = readStringField(schema, "templateKey")
			summary.Version = readStringField(schema, "version")
		}
	}
	return summary
}

func buildCardContentBundleSummary(card postgres.Card) *ContentBundleSummaryView {
	if card.EventContentBundleID == nil {
		return nil
	}
	summary := &ContentBundleSummaryView{
		ContentBundleID: *card.EventContentBundleID,
		Name:            card.EventContentBundleName,
		EntryURL:        card.EventContentEntryURL,
		AssetRootURL:    card.EventContentAssetRootURL,
	}
	if card.EventContentMetadataJSON != nil && strings.TrimSpace(*card.EventContentMetadataJSON) != "" {
		if metadata, err := decodeJSONObject(*card.EventContentMetadataJSON); err == nil {
			summary.BundleType = readStringField(metadata, "bundleType")
			summary.Version = readStringField(metadata, "version")
		}
	}
	return summary
}
