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"`
	CoverURL        *string `json:"coverUrl,omitempty"`
	DisplaySlot     string  `json:"displaySlot"`
	DisplayPriority int     `json:"displayPriority"`
	Event           *struct {
		ID          string  `json:"id"`
		DisplayName string  `json:"displayName"`
		Summary     *string `json:"summary,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 {
		item := CardResult{
			ID:              card.PublicID,
			Type:            card.CardType,
			Title:           card.Title,
			Subtitle:        card.Subtitle,
			CoverURL:        card.CoverURL,
			DisplaySlot:     card.DisplaySlot,
			DisplayPriority: card.DisplayPriority,
			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"`
			}{
				Summary: card.EventSummary,
			}
			if card.EventPublicID != nil {
				item.Event.ID = *card.EventPublicID
			}
			if card.EventDisplayName != nil {
				item.Event.DisplayName = *card.EventDisplayName
			}
		}
		results = append(results, item)
	}
	return results
}
