package workshop

import (
	"context"
	"encoding/json"
	"time"

	"github.com/google/uuid"
)

// ============================================================================
// Response Operations
// ============================================================================

// SaveResponse creates or updates a response
func (s *Store) SaveResponse(ctx context.Context, r *Response) error {
	r.UpdatedAt = time.Now().UTC()

	valueJSON, _ := json.Marshal(r.Value)

	// Upsert based on session_id, participant_id, field_id
	_, err := s.pool.Exec(ctx, `
		INSERT INTO workshop_responses (
			id, session_id, participant_id,
			step_number, field_id,
			value, value_type, status,
			created_at, updated_at
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7, $8, $9, $10
		)
		ON CONFLICT (session_id, participant_id, field_id) DO UPDATE SET
			value = $6,
			value_type = $7,
			status = $8,
			updated_at = $10
	`,
		uuid.New(), r.SessionID, r.ParticipantID,
		r.StepNumber, r.FieldID,
		valueJSON, r.ValueType, string(r.Status),
		r.UpdatedAt, r.UpdatedAt,
	)

	return err
}

// GetResponses retrieves responses for a session
func (s *Store) GetResponses(ctx context.Context, sessionID uuid.UUID, stepNumber *int) ([]Response, error) {
	query := `
		SELECT
			id, session_id, participant_id,
			step_number, field_id,
			value, value_type, status,
			reviewed_by, reviewed_at, review_notes,
			created_at, updated_at
		FROM workshop_responses WHERE session_id = $1`

	args := []interface{}{sessionID}
	if stepNumber != nil {
		query += " AND step_number = $2"
		args = append(args, *stepNumber)
	}

	query += " ORDER BY step_number ASC, field_id ASC"

	rows, err := s.pool.Query(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var responses []Response
	for rows.Next() {
		var r Response
		var status string
		var valueJSON []byte

		err := rows.Scan(
			&r.ID, &r.SessionID, &r.ParticipantID,
			&r.StepNumber, &r.FieldID,
			&valueJSON, &r.ValueType, &status,
			&r.ReviewedBy, &r.ReviewedAt, &r.ReviewNotes,
			&r.CreatedAt, &r.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}

		r.Status = ResponseStatus(status)
		json.Unmarshal(valueJSON, &r.Value)

		responses = append(responses, r)
	}

	return responses, nil
}

// ============================================================================
// Step Progress Operations
// ============================================================================

// UpdateStepProgress updates the progress for a step
func (s *Store) UpdateStepProgress(ctx context.Context, sessionID uuid.UUID, stepNumber int, status string, progress int) error {
	now := time.Now().UTC()

	_, err := s.pool.Exec(ctx, `
		INSERT INTO workshop_step_progress (
			id, session_id, step_number,
			status, progress, started_at
		) VALUES (
			$1, $2, $3, $4, $5, $6
		)
		ON CONFLICT (session_id, step_number) DO UPDATE SET
			status = $4,
			progress = $5,
			completed_at = CASE WHEN $4 = 'completed' THEN $6 ELSE NULL END
	`, uuid.New(), sessionID, stepNumber, status, progress, now)

	return err
}

// GetStepProgress retrieves step progress for a session
func (s *Store) GetStepProgress(ctx context.Context, sessionID uuid.UUID) ([]StepProgress, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT
			id, session_id, step_number,
			status, progress,
			started_at, completed_at, notes
		FROM workshop_step_progress WHERE session_id = $1
		ORDER BY step_number ASC
	`, sessionID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var progress []StepProgress
	for rows.Next() {
		var sp StepProgress
		err := rows.Scan(
			&sp.ID, &sp.SessionID, &sp.StepNumber,
			&sp.Status, &sp.Progress,
			&sp.StartedAt, &sp.CompletedAt, &sp.Notes,
		)
		if err != nil {
			return nil, err
		}
		progress = append(progress, sp)
	}

	return progress, nil
}

// ============================================================================
// Statistics
// ============================================================================

// GetSessionStats returns statistics for a session
func (s *Store) GetSessionStats(ctx context.Context, sessionID uuid.UUID) (*SessionStats, error) {
	stats := &SessionStats{
		ResponsesByStep:  make(map[int]int),
		ResponsesByField: make(map[string]int),
	}

	// Participant counts
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM workshop_participants WHERE session_id = $1",
		sessionID).Scan(&stats.ParticipantCount)

	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM workshop_participants WHERE session_id = $1 AND is_active = true",
		sessionID).Scan(&stats.ActiveParticipants)

	// Response count
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM workshop_responses WHERE session_id = $1",
		sessionID).Scan(&stats.ResponseCount)

	// Comment count
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM workshop_comments WHERE session_id = $1",
		sessionID).Scan(&stats.CommentCount)

	// Step progress
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM workshop_step_progress WHERE session_id = $1 AND status = 'completed'",
		sessionID).Scan(&stats.CompletedSteps)

	s.pool.QueryRow(ctx,
		"SELECT total_steps FROM workshop_sessions WHERE id = $1",
		sessionID).Scan(&stats.TotalSteps)

	// Responses by step
	rows, _ := s.pool.Query(ctx,
		"SELECT step_number, COUNT(*) FROM workshop_responses WHERE session_id = $1 GROUP BY step_number",
		sessionID)
	if rows != nil {
		defer rows.Close()
		for rows.Next() {
			var step, count int
			rows.Scan(&step, &count)
			stats.ResponsesByStep[step] = count
		}
	}

	// Responses by field
	rows, _ = s.pool.Query(ctx,
		"SELECT field_id, COUNT(*) FROM workshop_responses WHERE session_id = $1 GROUP BY field_id",
		sessionID)
	if rows != nil {
		defer rows.Close()
		for rows.Next() {
			var field string
			var count int
			rows.Scan(&field, &count)
			stats.ResponsesByField[field] = count
		}
	}

	// Average progress
	if stats.TotalSteps > 0 {
		stats.AverageProgress = (stats.CompletedSteps * 100) / stats.TotalSteps
	}

	return stats, nil
}

// GetSessionSummary returns a complete session summary
func (s *Store) GetSessionSummary(ctx context.Context, sessionID uuid.UUID) (*SessionSummary, error) {
	session, err := s.GetSession(ctx, sessionID)
	if err != nil || session == nil {
		return nil, err
	}

	participants, err := s.ListParticipants(ctx, sessionID)
	if err != nil {
		return nil, err
	}

	stepProgress, err := s.GetStepProgress(ctx, sessionID)
	if err != nil {
		return nil, err
	}

	var responseCount int
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM workshop_responses WHERE session_id = $1",
		sessionID).Scan(&responseCount)

	completedSteps := 0
	for _, sp := range stepProgress {
		if sp.Status == "completed" {
			completedSteps++
		}
	}

	progress := 0
	if session.TotalSteps > 0 {
		progress = (completedSteps * 100) / session.TotalSteps
	}

	return &SessionSummary{
		Session:         session,
		Participants:    participants,
		StepProgress:    stepProgress,
		TotalResponses:  responseCount,
		CompletedSteps:  completedSteps,
		OverallProgress: progress,
	}, nil
}
