package service

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

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

type EntryHomeService struct {
	store *postgres.Store
}

type EntryHomeInput struct {
	UserID        string
	ChannelCode   string
	ChannelType   string
	PlatformAppID string
	TenantCode    string
}

type EntryHomeResult struct {
	User struct {
		ID        string  `json:"id"`
		PublicID  string  `json:"publicId"`
		Status    string  `json:"status"`
		Nickname  *string `json:"nickname,omitempty"`
		AvatarURL *string `json:"avatarUrl,omitempty"`
	} `json:"user"`
	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"`
	OngoingSession *EntrySessionSummary `json:"ongoingSession,omitempty"`
	RecentSession  *EntrySessionSummary `json:"recentSession,omitempty"`
}

type EntrySessionSummary struct {
	ID          string  `json:"id"`
	Status      string  `json:"status"`
	EventID     string  `json:"eventId"`
	EventName   string  `json:"eventName"`
	ReleaseID   *string `json:"releaseId,omitempty"`
	ConfigLabel *string `json:"configLabel,omitempty"`
	VariantID   *string `json:"variantId,omitempty"`
	VariantName *string `json:"variantName,omitempty"`
	RouteCode   *string `json:"routeCode,omitempty"`
	LaunchedAt  string  `json:"launchedAt"`
	StartedAt   *string `json:"startedAt,omitempty"`
	EndedAt     *string `json:"endedAt,omitempty"`
}

func NewEntryHomeService(store *postgres.Store) *EntryHomeService {
	return &EntryHomeService{store: store}
}

func (s *EntryHomeService) GetEntryHome(ctx context.Context, input EntryHomeInput) (*EntryHomeResult, error) {
	input.UserID = strings.TrimSpace(input.UserID)
	if input.UserID == "" {
		return nil, apperr.New(http.StatusUnauthorized, "unauthorized", "user is required")
	}

	user, err := s.store.GetUserByID(ctx, s.store.Pool(), input.UserID)
	if err != nil {
		return nil, err
	}
	if user == nil {
		return nil, apperr.New(http.StatusNotFound, "user_not_found", "user not found")
	}

	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")
	}

	cards, err := s.store.ListCardsForEntry(ctx, entry.TenantID, &entry.ID, "home_primary", nowUTC(), 20)
	if err != nil {
		return nil, err
	}

	sessions, err := s.store.ListSessionsByUserID(ctx, user.ID, 10)
	if err != nil {
		return nil, err
	}

	result := &EntryHomeResult{
		Cards: mapCards(cards),
	}
	result.User.ID = user.ID
	result.User.PublicID = user.PublicID
	result.User.Status = user.Status
	result.User.Nickname = user.Nickname
	result.User.AvatarURL = user.AvatarURL
	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

	if len(sessions) > 0 {
		recent := buildEntrySessionSummary(&sessions[0])
		result.RecentSession = &recent
	}

	for i := range sessions {
		if isSessionOngoingStatus(sessions[i].Status) {
			ongoing := buildEntrySessionSummary(&sessions[i])
			result.OngoingSession = &ongoing
			break
		}
	}

	return result, nil
}

func buildEntrySessionSummary(session *postgres.Session) EntrySessionSummary {
	summary := EntrySessionSummary{
		ID:          session.SessionPublicID,
		Status:      session.Status,
		VariantID:   session.VariantID,
		VariantName: session.VariantName,
		RouteCode:   session.RouteCode,
		LaunchedAt:  session.LaunchedAt.Format(timeRFC3339),
	}
	if session.EventPublicID != nil {
		summary.EventID = *session.EventPublicID
	}
	if session.EventDisplayName != nil {
		summary.EventName = *session.EventDisplayName
	}
	summary.ReleaseID = session.ReleasePublicID
	summary.ConfigLabel = session.ConfigLabel
	if session.StartedAt != nil {
		value := session.StartedAt.Format(timeRFC3339)
		summary.StartedAt = &value
	}
	if session.EndedAt != nil {
		value := session.EndedAt.Format(timeRFC3339)
		summary.EndedAt = &value
	}
	return summary
}
