package service

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

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

type EventPlayService struct {
	store *postgres.Store
}

type EventPlayInput struct {
	EventPublicID string
	UserID        string
}

type EventPlayResult struct {
	Event struct {
		ID          string  `json:"id"`
		Slug        string  `json:"slug"`
		DisplayName string  `json:"displayName"`
		Summary     *string `json:"summary,omitempty"`
		Status      string  `json:"status"`
	} `json:"event"`
	Release *struct {
		ID                     string  `json:"id"`
		ConfigLabel            string  `json:"configLabel"`
		ManifestURL            string  `json:"manifestUrl"`
		ManifestChecksumSha256 *string `json:"manifestChecksumSha256,omitempty"`
		RouteCode              *string `json:"routeCode,omitempty"`
	} `json:"release,omitempty"`
	ResolvedRelease      *ResolvedReleaseView      `json:"resolvedRelease,omitempty"`
	Runtime              *RuntimeSummaryView       `json:"runtime,omitempty"`
	CurrentPresentation  *PresentationSummaryView  `json:"currentPresentation,omitempty"`
	CurrentContentBundle *ContentBundleSummaryView `json:"currentContentBundle,omitempty"`
	Play                 struct {
		AssignmentMode *string              `json:"assignmentMode,omitempty"`
		CourseVariants []CourseVariantView  `json:"courseVariants,omitempty"`
		CanLaunch      bool                 `json:"canLaunch"`
		PrimaryAction  string               `json:"primaryAction"`
		Reason         string               `json:"reason"`
		LaunchSource   string               `json:"launchSource,omitempty"`
		OngoingSession *EntrySessionSummary `json:"ongoingSession,omitempty"`
		RecentSession  *EntrySessionSummary `json:"recentSession,omitempty"`
	} `json:"play"`
}

func NewEventPlayService(store *postgres.Store) *EventPlayService {
	return &EventPlayService{store: store}
}

func (s *EventPlayService) GetEventPlay(ctx context.Context, input EventPlayInput) (*EventPlayResult, error) {
	input.EventPublicID = strings.TrimSpace(input.EventPublicID)
	input.UserID = strings.TrimSpace(input.UserID)
	if input.EventPublicID == "" {
		return nil, apperr.New(http.StatusBadRequest, "invalid_params", "event id is required")
	}
	if input.UserID == "" {
		return nil, apperr.New(http.StatusUnauthorized, "unauthorized", "user is required")
	}

	event, err := s.store.GetEventByPublicID(ctx, input.EventPublicID)
	if err != nil {
		return nil, err
	}
	if event == nil {
		return nil, apperr.New(http.StatusNotFound, "event_not_found", "event not found")
	}

	sessions, err := s.store.ListSessionsByUserAndEvent(ctx, input.UserID, event.ID, 10)
	if err != nil {
		return nil, err
	}

	result := &EventPlayResult{}
	result.Event.ID = event.PublicID
	result.Event.Slug = event.Slug
	result.Event.DisplayName = event.DisplayName
	result.Event.Summary = event.Summary
	result.Event.Status = event.Status
	variantPlan := resolveVariantPlan(event.ReleasePayloadJSON)
	result.Play.AssignmentMode = variantPlan.AssignmentMode
	if len(variantPlan.CourseVariants) > 0 {
		result.Play.CourseVariants = variantPlan.CourseVariants
	}
	if event.CurrentReleasePubID != nil && event.ConfigLabel != nil && event.ManifestURL != nil {
		result.Release = &struct {
			ID                     string  `json:"id"`
			ConfigLabel            string  `json:"configLabel"`
			ManifestURL            string  `json:"manifestUrl"`
			ManifestChecksumSha256 *string `json:"manifestChecksumSha256,omitempty"`
			RouteCode              *string `json:"routeCode,omitempty"`
		}{
			ID:                     *event.CurrentReleasePubID,
			ConfigLabel:            *event.ConfigLabel,
			ManifestURL:            *event.ManifestURL,
			ManifestChecksumSha256: event.ManifestChecksum,
			RouteCode:              event.RouteCode,
		}
	}
	result.ResolvedRelease = buildResolvedReleaseFromEvent(event, LaunchSourceEventCurrentRelease)
	result.Runtime = buildRuntimeSummaryFromEvent(event)
	result.CurrentPresentation = buildPresentationSummaryFromEvent(event)
	if enrichedPresentation, err := loadPresentationSummaryByPublicID(ctx, s.store, event.PresentationID); err != nil {
		return nil, err
	} else if enrichedPresentation != nil {
		result.CurrentPresentation = enrichedPresentation
	}
	result.CurrentContentBundle = buildContentBundleSummaryFromEvent(event)
	if enrichedBundle, err := loadContentBundleSummaryByPublicID(ctx, s.store, event.ContentBundleID); err != nil {
		return nil, err
	} else if enrichedBundle != nil {
		result.CurrentContentBundle = enrichedBundle
	}

	if len(sessions) > 0 {
		recent := buildEntrySessionSummary(&sessions[0])
		result.Play.RecentSession = &recent
	}
	for i := range sessions {
		if isSessionOngoingStatus(sessions[i].Status) {
			ongoing := buildEntrySessionSummary(&sessions[i])
			result.Play.OngoingSession = &ongoing
			break
		}
	}

	canLaunch, launchReason := evaluateEventLaunchReadiness(event)
	result.Play.CanLaunch = canLaunch
	if canLaunch {
		result.Play.LaunchSource = LaunchSourceEventCurrentRelease
	}

	switch {
	case result.Play.OngoingSession != nil:
		result.Play.PrimaryAction = "continue"
		result.Play.Reason = "user has an ongoing session for this event"
	case canLaunch:
		result.Play.PrimaryAction = "start"
		result.Play.Reason = launchReason
	case result.Play.RecentSession != nil:
		result.Play.PrimaryAction = "review_last_result"
		result.Play.Reason = launchReason + ", but user has previous session history"
	default:
		result.Play.PrimaryAction = "unavailable"
		result.Play.Reason = launchReason
	}

	return result, nil
}
