package scoring

import (
	"context"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgxpool"
)

type Repository interface {
	GetScoringData(ctx context.Context, sessionID uuid.UUID) ([]ScoringDataRow, error)
	GetScoringRule(ctx context.Context, testTypeID uuid.UUID) (*ScoringRule, error)
	SaveResult(ctx context.Context, result *CandidateResult) error
}

type repository struct {
	db *pgxpool.Pool
}

func NewRepository(db *pgxpool.Pool) Repository {
	return &repository{db: db}
}

// GetScoringData performs a single join query to avoid N+1 issues when fetching candidate answers, questions, and question items.
func (r *repository) GetScoringData(ctx context.Context, sessionID uuid.UUID) ([]ScoringDataRow, error) {
	query := `
		SELECT 
			ca.candidate_id,
			q.test_type_id,
			q.id AS question_id,
			q.question_type,
			q.order_number,
			q.answer_key,
			q.scoring_weight,
			COALESCE(
				json_agg(
					json_build_object(
						'id', qi.id,
						'item_order', qi.item_order,
						'meta', qi.meta
					)
				) FILTER (WHERE qi.id IS NOT NULL), '[]'
			) AS items_json,
			ca.answer
		FROM candidate_answers ca
		JOIN questions q ON ca.question_id = q.id
		LEFT JOIN question_items qi ON q.id = qi.question_id
		WHERE ca.session_id = $1
		GROUP BY ca.candidate_id, q.test_type_id, q.id, q.question_type, q.order_number, q.answer_key, q.scoring_weight, ca.answer
		ORDER BY q.order_number ASC
	`
	rows, err := r.db.Query(ctx, query, sessionID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var data []ScoringDataRow
	for rows.Next() {
		var row ScoringDataRow
		if err := rows.Scan(
			&row.CandidateID,
			&row.TestTypeID,
			&row.QuestionID,
			&row.QuestionType,
			&row.OrderNumber,
			&row.AnswerKey,
			&row.ScoringWeight,
			&row.ItemsJSON,
			&row.Answer,
		); err != nil {
			return nil, err
		}
		data = append(data, row)
	}

	return data, nil
}

func (r *repository) GetScoringRule(ctx context.Context, testTypeID uuid.UUID) (*ScoringRule, error) {
	query := `SELECT id, test_type_id, rules FROM scoring_rules WHERE test_type_id = $1 ORDER BY version DESC LIMIT 1`
	var rule ScoringRule
	err := r.db.QueryRow(ctx, query, testTypeID).Scan(&rule.ID, &rule.TestTypeID, &rule.Rules)
	if err != nil {
		return nil, err
	}
	return &rule, nil
}

func (r *repository) SaveResult(ctx context.Context, res *CandidateResult) error {
	query := `
		INSERT INTO candidate_results (session_id, candidate_id, test_type_id, total_score, normalized_score, result, interpretation) 
		VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id, created_at
	`
	return r.db.QueryRow(ctx, query, res.SessionID, res.CandidateID, res.TestTypeID, res.TotalScore, res.NormalizedScore, res.Result, res.Interpretation).Scan(&res.ID, &res.CreatedAt)
}
