package service

import (
	"context"
	"strings"

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

const (
	LaunchSourceEventCurrentRelease = "event_current_release"
	LaunchModeManifestRelease       = "manifest_release"
)

type ResolvedReleaseView struct {
	LaunchMode             string  `json:"launchMode"`
	Source                 string  `json:"source"`
	EventID                string  `json:"eventId"`
	ReleaseID              string  `json:"releaseId"`
	ConfigLabel            string  `json:"configLabel"`
	ManifestURL            string  `json:"manifestUrl"`
	ManifestChecksumSha256 *string `json:"manifestChecksumSha256,omitempty"`
	RouteCode              *string `json:"routeCode,omitempty"`
}

type RuntimeSummaryView struct {
	RuntimeBindingID  string  `json:"runtimeBindingId"`
	PlaceID           string  `json:"placeId"`
	PlaceName         *string `json:"placeName,omitempty"`
	MapID             string  `json:"mapId"`
	MapName           *string `json:"mapName,omitempty"`
	TileReleaseID     string  `json:"tileReleaseId"`
	CourseSetID       string  `json:"courseSetId"`
	CourseVariantID   string  `json:"courseVariantId"`
	CourseVariantName *string `json:"courseVariantName,omitempty"`
	RouteCode         *string `json:"routeCode,omitempty"`
}

type PresentationSummaryView struct {
	PresentationID   string  `json:"presentationId"`
	Name             *string `json:"name,omitempty"`
	PresentationType *string `json:"presentationType,omitempty"`
	TemplateKey      *string `json:"templateKey,omitempty"`
	Version          *string `json:"version,omitempty"`
}

type ContentBundleSummaryView struct {
	ContentBundleID string  `json:"contentBundleId"`
	Name            *string `json:"name,omitempty"`
	BundleType      *string `json:"bundleType,omitempty"`
	Version         *string `json:"version,omitempty"`
	EntryURL        *string `json:"entryUrl,omitempty"`
	AssetRootURL    *string `json:"assetRootUrl,omitempty"`
}

func buildResolvedReleaseFromEvent(event *postgres.Event, source string) *ResolvedReleaseView {
	if event == nil || event.CurrentReleasePubID == nil || event.ConfigLabel == nil || event.ManifestURL == nil {
		return nil
	}

	return &ResolvedReleaseView{
		LaunchMode:             LaunchModeManifestRelease,
		Source:                 source,
		EventID:                event.PublicID,
		ReleaseID:              *event.CurrentReleasePubID,
		ConfigLabel:            *event.ConfigLabel,
		ManifestURL:            *event.ManifestURL,
		ManifestChecksumSha256: event.ManifestChecksum,
		RouteCode:              event.RouteCode,
	}
}

func buildRuntimeSummaryFromEvent(event *postgres.Event) *RuntimeSummaryView {
	if event == nil ||
		event.RuntimeBindingID == nil ||
		event.PlacePublicID == nil ||
		event.MapAssetPublicID == nil ||
		event.TileReleasePublicID == nil ||
		event.CourseSetPublicID == nil ||
		event.CourseVariantID == nil {
		return nil
	}

	return &RuntimeSummaryView{
		RuntimeBindingID:  *event.RuntimeBindingID,
		PlaceID:           *event.PlacePublicID,
		PlaceName:         event.PlaceName,
		MapID:             *event.MapAssetPublicID,
		MapName:           event.MapAssetName,
		TileReleaseID:     *event.TileReleasePublicID,
		CourseSetID:       *event.CourseSetPublicID,
		CourseVariantID:   *event.CourseVariantID,
		CourseVariantName: event.CourseVariantName,
		RouteCode:         firstNonNilString(event.RuntimeRouteCode, event.RouteCode),
	}
}

func buildRuntimeSummaryFromRelease(release *postgres.EventRelease) *RuntimeSummaryView {
	if release == nil ||
		release.RuntimeBindingID == nil ||
		release.PlacePublicID == nil ||
		release.MapAssetPublicID == nil ||
		release.TileReleaseID == nil ||
		release.CourseSetID == nil ||
		release.CourseVariantID == nil {
		return nil
	}

	return &RuntimeSummaryView{
		RuntimeBindingID:  *release.RuntimeBindingID,
		PlaceID:           *release.PlacePublicID,
		PlaceName:         release.PlaceName,
		MapID:             *release.MapAssetPublicID,
		MapName:           release.MapAssetName,
		TileReleaseID:     *release.TileReleaseID,
		CourseSetID:       *release.CourseSetID,
		CourseVariantID:   *release.CourseVariantID,
		CourseVariantName: release.CourseVariantName,
		RouteCode:         firstNonNilString(release.RuntimeRouteCode, release.RouteCode),
	}
}

func buildPresentationSummaryFromEvent(event *postgres.Event) *PresentationSummaryView {
	if event == nil || event.PresentationID == nil {
		return nil
	}
	return &PresentationSummaryView{
		PresentationID:   *event.PresentationID,
		Name:             event.PresentationName,
		PresentationType: event.PresentationType,
	}
}

func buildPresentationSummaryFromRelease(release *postgres.EventRelease) *PresentationSummaryView {
	if release == nil || release.PresentationID == nil {
		return nil
	}
	return &PresentationSummaryView{
		PresentationID:   *release.PresentationID,
		Name:             release.PresentationName,
		PresentationType: release.PresentationType,
	}
}

func buildContentBundleSummaryFromEvent(event *postgres.Event) *ContentBundleSummaryView {
	if event == nil || event.ContentBundleID == nil {
		return nil
	}
	return &ContentBundleSummaryView{
		ContentBundleID: *event.ContentBundleID,
		Name:            event.ContentBundleName,
		EntryURL:        event.ContentEntryURL,
		AssetRootURL:    event.ContentAssetRootURL,
	}
}

func buildContentBundleSummaryFromRelease(release *postgres.EventRelease) *ContentBundleSummaryView {
	if release == nil || release.ContentBundleID == nil {
		return nil
	}
	return &ContentBundleSummaryView{
		ContentBundleID: *release.ContentBundleID,
		Name:            release.ContentBundleName,
		EntryURL:        release.ContentEntryURL,
		AssetRootURL:    release.ContentAssetURL,
	}
}

func buildResolvedReleaseFromSession(session *postgres.Session, source string) *ResolvedReleaseView {
	if session == nil || session.ReleasePublicID == nil || session.ConfigLabel == nil || session.ManifestURL == nil {
		return nil
	}

	view := &ResolvedReleaseView{
		LaunchMode:             LaunchModeManifestRelease,
		Source:                 source,
		ReleaseID:              *session.ReleasePublicID,
		ConfigLabel:            *session.ConfigLabel,
		ManifestURL:            *session.ManifestURL,
		ManifestChecksumSha256: session.ManifestChecksum,
		RouteCode:              session.RouteCode,
	}
	if session.EventPublicID != nil {
		view.EventID = *session.EventPublicID
	}
	return view
}

func loadPresentationSummaryByPublicID(ctx context.Context, store *postgres.Store, publicID *string) (*PresentationSummaryView, error) {
	if store == nil || publicID == nil || strings.TrimSpace(*publicID) == "" {
		return nil, nil
	}
	record, err := store.GetEventPresentationByPublicID(ctx, strings.TrimSpace(*publicID))
	if err != nil {
		return nil, err
	}
	if record == nil {
		return nil, nil
	}
	return buildPresentationSummaryFromRecord(record)
}

func loadContentBundleSummaryByPublicID(ctx context.Context, store *postgres.Store, publicID *string) (*ContentBundleSummaryView, error) {
	if store == nil || publicID == nil || strings.TrimSpace(*publicID) == "" {
		return nil, nil
	}
	record, err := store.GetContentBundleByPublicID(ctx, strings.TrimSpace(*publicID))
	if err != nil {
		return nil, err
	}
	if record == nil {
		return nil, nil
	}
	return buildContentBundleSummaryFromRecord(record)
}

func buildPresentationSummaryFromRecord(record *postgres.EventPresentation) (*PresentationSummaryView, error) {
	if record == nil {
		return nil, nil
	}
	summary := &PresentationSummaryView{
		PresentationID:   record.PublicID,
		Name:             &record.Name,
		PresentationType: &record.PresentationType,
	}
	schema, err := decodeJSONObject(record.SchemaJSON)
	if err != nil {
		return nil, err
	}
	summary.TemplateKey = readStringField(schema, "templateKey")
	summary.Version = readStringField(schema, "version")
	return summary, nil
}

func buildContentBundleSummaryFromRecord(record *postgres.ContentBundle) (*ContentBundleSummaryView, error) {
	if record == nil {
		return nil, nil
	}
	summary := &ContentBundleSummaryView{
		ContentBundleID: record.PublicID,
		Name:            &record.Name,
		EntryURL:        record.EntryURL,
		AssetRootURL:    record.AssetRootURL,
	}
	metadata, err := decodeJSONObject(record.MetadataJSON)
	if err != nil {
		return nil, err
	}
	summary.BundleType = readStringField(metadata, "bundleType")
	summary.Version = readStringField(metadata, "version")
	return summary, nil
}

func readStringField(object map[string]any, key string) *string {
	if object == nil {
		return nil
	}
	value, ok := object[key]
	if !ok {
		return nil
	}
	text, ok := value.(string)
	if !ok {
		return nil
	}
	text = strings.TrimSpace(text)
	if text == "" {
		return nil
	}
	return &text
}

func firstNonNilString(values ...*string) *string {
	for _, value := range values {
		if value != nil {
			return value
		}
	}
	return nil
}
