package service

import (
	"context"
	"encoding/json"
	"net/http"

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

type ResultService struct {
	store *postgres.Store
}

type SessionResultView struct {
	Session EntrySessionSummary  `json:"session"`
	Result  ResultSummaryPayload `json:"result"`
}

type ResultSummaryPayload struct {
	Status            string         `json:"status"`
	FinalDurationSec  *int           `json:"finalDurationSec,omitempty"`
	FinalScore        *int           `json:"finalScore,omitempty"`
	CompletedControls *int           `json:"completedControls,omitempty"`
	TotalControls     *int           `json:"totalControls,omitempty"`
	DistanceMeters    *float64       `json:"distanceMeters,omitempty"`
	AverageSpeedKmh   *float64       `json:"averageSpeedKmh,omitempty"`
	MaxHeartRateBpm   *int           `json:"maxHeartRateBpm,omitempty"`
	Summary           map[string]any `json:"summary,omitempty"`
}

func NewResultService(store *postgres.Store) *ResultService {
	return &ResultService{store: store}
}

func (s *ResultService) GetSessionResult(ctx context.Context, sessionPublicID, userID string) (*SessionResultView, error) {
	record, err := s.store.GetSessionResultByPublicID(ctx, sessionPublicID)
	if err != nil {
		return nil, err
	}
	if record == nil {
		return nil, apperr.New(http.StatusNotFound, "session_not_found", "session not found")
	}
	if userID != "" && record.UserID != userID {
		return nil, apperr.New(http.StatusForbidden, "session_forbidden", "session does not belong to current user")
	}
	return buildSessionResultView(record), nil
}

func (s *ResultService) ListMyResults(ctx context.Context, userID string, limit int) ([]SessionResultView, error) {
	if userID == "" {
		return nil, apperr.New(http.StatusUnauthorized, "unauthorized", "user is required")
	}

	records, err := s.store.ListSessionResultsByUserID(ctx, userID, limit)
	if err != nil {
		return nil, err
	}

	results := make([]SessionResultView, 0, len(records))
	for i := range records {
		results = append(results, *buildSessionResultView(&records[i]))
	}
	return results, nil
}

func buildSessionResultView(record *postgres.SessionResultRecord) *SessionResultView {
	view := &SessionResultView{
		Session: buildEntrySessionSummary(&record.Session),
		Result: ResultSummaryPayload{
			Status: record.Status,
		},
	}

	if record.Result != nil {
		view.Result.Status = record.Result.ResultStatus
		view.Result.FinalDurationSec = record.Result.FinalDurationSec
		view.Result.FinalScore = record.Result.FinalScore
		view.Result.CompletedControls = record.Result.CompletedControls
		view.Result.TotalControls = record.Result.TotalControls
		view.Result.DistanceMeters = record.Result.DistanceMeters
		view.Result.AverageSpeedKmh = record.Result.AverageSpeedKmh
		view.Result.MaxHeartRateBpm = record.Result.MaxHeartRateBpm
		if record.Result.SummaryJSON != "" {
			summary := map[string]any{}
			if err := json.Unmarshal([]byte(record.Result.SummaryJSON), &summary); err == nil && len(summary) > 0 {
				view.Result.Summary = summary
			}
		}
	}

	return view
}
