-- name: CreateAssignment :one
INSERT INTO assignments (
    classroom_id,
    teacher_id,
    title,
    instructions,
    status,
    due_at,
    published_at,
    pass_threshold
) VALUES (
    $1,
    $2,
    $3,
    $4,
    $5,
    $6,
    $7,
    $8
)
RETURNING *;

-- name: AssignStudentToAssignment :exec
INSERT INTO assignment_assignees (
  assignment_id,
  student_id
) VALUES (
  $1,
  $2
)
ON CONFLICT (assignment_id, student_id) DO NOTHING;

-- name: DeleteAssignmentAssignee :exec
DELETE FROM assignment_assignees
WHERE assignment_id = $1
  AND student_id = $2;

-- name: GetAssignmentAssignee :one
SELECT *
FROM assignment_assignees
WHERE assignment_id = $1
  AND student_id = $2;

-- name: UpdateAssignmentAIReview :one
UPDATE assignment_assignees
SET ai_feedback = $3,
    next_step_outcome = NULLIF($4::text, '')::assignment_next_step_outcome
WHERE assignment_id = $1
  AND student_id = $2
RETURNING *;

-- name: UpdateAssignmentRedoPlan :one
UPDATE assignment_assignees
SET redo_plan = NULLIF($3::text, ''),
    redo_plan_generated_at = CASE
        WHEN NULLIF($3::text, '') IS NULL THEN NULL
        ELSE NOW()
    END
WHERE assignment_id = $1
  AND student_id = $2
RETURNING *;

-- name: GetAssignmentRedoPlan :one
SELECT
    assignment_id,
    student_id,
    redo_plan,
    redo_plan_generated_at
FROM assignment_assignees
WHERE assignment_id = $1
  AND student_id = $2;

-- name: UpdateAssignmentTeacherFeedback :one
WITH student_question_set AS (
    SELECT asq.assignment_id, asq.question_id, asq.position
    FROM assignment_student_questions asq
    WHERE asq.assignment_id = $1
      AND asq.student_id = $2
), selected_questions AS (
    SELECT assignment_id, question_id, position
    FROM student_question_set
    UNION ALL
    SELECT aq.assignment_id, aq.question_id, aq.position
    FROM assignment_questions aq
    WHERE aq.assignment_id = $1
      AND NOT EXISTS (SELECT 1 FROM student_question_set)
), score_summary AS (
    SELECT CASE
            WHEN COUNT(sa.id) = 0 THEN NULL
            ELSE ROUND((AVG(
                CASE
                    WHEN sa.is_correct IS NULL THEN COALESCE(sa.review_understanding_score, 0)::NUMERIC
                    ELSE (
                        ((CASE WHEN sa.is_correct THEN 1 ELSE 0 END)::NUMERIC) + COALESCE(sa.review_understanding_score, 0)::NUMERIC
                    ) / 2
                END
            ) * 10)::NUMERIC, 2)
        END AS overall_score
    FROM selected_questions aq
    LEFT JOIN student_answers sa
        ON sa.assignment_id = aq.assignment_id
       AND sa.question_id = aq.question_id
       AND sa.student_id = $2
    WHERE aq.assignment_id = $1
), updated AS (
    UPDATE assignment_assignees aa
    SET teacher_feedback = $3,
        pass_status_override = NULLIF($4::text, '')::assignment_pass_status,
        next_step_outcome = NULLIF($5::text, '')::assignment_next_step_outcome,
        overall_score = (SELECT overall_score FROM score_summary),
        pass_status = COALESCE(
            NULLIF($4::text, '')::assignment_pass_status,
            CASE
                WHEN (SELECT overall_score FROM score_summary) IS NULL THEN 'pending'::assignment_pass_status
                WHEN (SELECT overall_score FROM score_summary) >= a.pass_threshold THEN 'pass'::assignment_pass_status
                ELSE 'no_pass'::assignment_pass_status
            END
        )
    FROM assignments a
    WHERE aa.assignment_id = $1
      AND aa.student_id = $2
      AND a.id = aa.assignment_id
    RETURNING aa.*
)
SELECT *
FROM updated;

-- name: AddQuestionToAssignment :exec
INSERT INTO assignment_questions (
    assignment_id,
    question_id,
    position
) VALUES (
    $1,
    $2,
    $3
)
ON CONFLICT (assignment_id, question_id) DO UPDATE
SET position = EXCLUDED.position;

-- name: DeleteAssignmentStudentQuestions :exec
DELETE FROM assignment_student_questions
WHERE assignment_id = $1
  AND student_id = $2;

-- name: AddAssignmentStudentQuestion :one
INSERT INTO assignment_student_questions (
    assignment_id,
    student_id,
    question_id,
    position,
    source_bucket,
    source_topic,
    source_difficulty,
    generator_seed
) VALUES (
    $1,
    $2,
    $3,
    $4,
    $5,
    $6,
    $7,
    $8
)
RETURNING *;

-- name: ListAssignmentStudentQuestions :many
SELECT *
FROM assignment_student_questions
WHERE assignment_id = $1
  AND student_id = $2
ORDER BY position ASC, id ASC;

-- name: ListGeneratedQuestionsForAssignmentStudent :many
SELECT
    asq.id,
    asq.assignment_id,
    asq.student_id,
    asq.question_id,
    asq.position,
    asq.source_bucket,
    asq.source_topic,
    asq.source_difficulty,
    asq.generator_seed,
    asq.created_at,
    q.author_teacher_id,
    q.title,
    q.prompt,
    q.subject,
    q.source,
    q.status,
    q.created_at AS question_created_at,
    q.updated_at AS question_updated_at,
    q.correct_answer,
    q.topic,
    q.difficulty
FROM assignment_student_questions asq
JOIN questions q ON q.id = asq.question_id
WHERE asq.assignment_id = $1
  AND asq.student_id = $2
ORDER BY asq.position ASC, asq.id ASC;

-- name: ListAssignmentsByTeacher :many
SELECT *
FROM assignments
WHERE teacher_id = $1
ORDER BY created_at DESC;

-- name: ListAssignmentsForStudent :many
SELECT a.*
FROM assignment_assignees aa
JOIN assignments a ON a.id = aa.assignment_id
WHERE aa.student_id = $1
ORDER BY a.created_at DESC;

-- name: GetAssignmentByID :one
SELECT *
FROM assignments
WHERE id = $1;

-- name: UpdateAssignmentDraft :one
UPDATE assignments
SET classroom_id = $2,
    title = $3,
    instructions = $4,
    due_at = $5,
    pass_threshold = $6,
    updated_at = NOW()
WHERE id = $1
RETURNING *;

-- name: CloseAssignment :one
UPDATE assignments
SET status = 'closed'::assignment_status,
    updated_at = NOW()
WHERE id = $1
RETURNING *;

-- name: ListQuestionsForAssignment :many
SELECT
    aq.assignment_id,
    aq.question_id,
    aq.position,
    q.author_teacher_id,
    q.title,
    q.prompt,
    q.subject,
    q.source,
    q.status,
    q.created_at,
    q.updated_at
FROM assignment_questions aq
JOIN questions q ON q.id = aq.question_id
WHERE aq.assignment_id = $1
ORDER BY aq.position ASC, aq.question_id ASC;

-- name: GetAssignmentReviewSummary :one
WITH student_question_set AS (
    SELECT asq.student_id, asq.question_id, asq.position
    FROM assignment_student_questions asq
    WHERE asq.assignment_id = $1
),
students_with_personalized AS (
    SELECT DISTINCT student_id
    FROM student_question_set
),
selected_questions AS (
    SELECT student_id, question_id, position
    FROM student_question_set
    UNION ALL
    SELECT aa.student_id, aq.question_id, aq.position
    FROM assignment_assignees aa
    JOIN assignment_questions aq ON aq.assignment_id = aa.assignment_id
    WHERE aa.assignment_id = $1
      AND NOT EXISTS (
            SELECT 1
            FROM students_with_personalized swp
            WHERE swp.student_id = aa.student_id
        )
),
student_states AS (
    SELECT
        aa.student_id,
        COUNT(sq.question_id)::BIGINT AS total_questions,
        CASE
            WHEN COUNT(sa.id) = 0 THEN 'not_started'::answer_status
            WHEN COUNT(sq.question_id) > 0
                AND COUNT(sa.id) FILTER (WHERE sa.status = 'reviewed') = COUNT(sq.question_id)
                THEN 'reviewed'::answer_status
            WHEN COUNT(sa.id) FILTER (WHERE sa.status = 'submitted') > 0 THEN 'submitted'::answer_status
            WHEN COUNT(sa.id) FILTER (WHERE sa.status = 'in_progress') > 0 THEN 'in_progress'::answer_status
            WHEN COUNT(sa.id) FILTER (WHERE sa.status = 'reviewed') > 0 THEN 'in_progress'::answer_status
            ELSE 'not_started'::answer_status
        END AS review_status
    FROM assignment_assignees aa
    LEFT JOIN selected_questions sq
        ON sq.student_id = aa.student_id
    LEFT JOIN student_answers sa
        ON sa.assignment_id = aa.assignment_id
       AND sa.question_id = sq.question_id
       AND sa.student_id = aa.student_id
    WHERE aa.assignment_id = $1
    GROUP BY aa.student_id
)
SELECT
    $1::BIGINT AS assignment_id,
    COALESCE(MAX(student_states.total_questions), 0)::BIGINT AS total_questions,
    COUNT(*)::BIGINT AS total_assigned,
    COUNT(*) FILTER (WHERE review_status = 'not_started')::BIGINT AS not_started,
    COUNT(*) FILTER (WHERE review_status = 'in_progress')::BIGINT AS in_progress,
    COUNT(*) FILTER (WHERE review_status = 'submitted')::BIGINT AS submitted,
    COUNT(*) FILTER (WHERE review_status = 'reviewed')::BIGINT AS reviewed
FROM student_states;

-- name: ListAssignmentReviewQueue :many
WITH student_question_set AS (
    SELECT asq.student_id, asq.question_id, asq.position
    FROM assignment_student_questions asq
    WHERE asq.assignment_id = $1
),
students_with_personalized AS (
    SELECT DISTINCT student_id
    FROM student_question_set
),
selected_questions AS (
    SELECT student_id, question_id, position
    FROM student_question_set
    UNION ALL
    SELECT aa.student_id, aq.question_id, aq.position
    FROM assignment_assignees aa
    JOIN assignment_questions aq ON aq.assignment_id = aa.assignment_id
    WHERE aa.assignment_id = $1
      AND NOT EXISTS (
            SELECT 1
            FROM students_with_personalized swp
            WHERE swp.student_id = aa.student_id
        )
),
student_states AS (
    SELECT
        aa.assignment_id,
        aa.student_id,
        aa.next_step_outcome,
        u.full_name AS student_name,
        u.email AS student_email,
        COUNT(sq.question_id)::BIGINT AS total_questions,
        COUNT(sa.id)::BIGINT AS answered_questions,
        COUNT(sa.id) FILTER (WHERE sa.status = 'reviewed')::BIGINT AS reviewed_questions,
        COUNT(sa.id) FILTER (WHERE sa.status = 'submitted')::BIGINT AS submitted_questions,
        COUNT(sa.id) FILTER (WHERE sa.status = 'in_progress')::BIGINT AS in_progress_questions,
        MAX(sa.submitted_at)::timestamptz AS latest_submitted_at,
        MAX(sa.reviewed_at)::timestamptz AS latest_reviewed_at,
        CASE
            WHEN COUNT(sa.id) = 0 THEN 'not_started'::answer_status
            WHEN COUNT(sq.question_id) > 0
                AND COUNT(sa.id) FILTER (WHERE sa.status = 'reviewed') = COUNT(sq.question_id)
                THEN 'reviewed'::answer_status
            WHEN COUNT(sa.id) FILTER (WHERE sa.status = 'submitted') > 0 THEN 'submitted'::answer_status
            WHEN COUNT(sa.id) FILTER (WHERE sa.status = 'in_progress') > 0 THEN 'in_progress'::answer_status
            WHEN COUNT(sa.id) FILTER (WHERE sa.status = 'reviewed') > 0 THEN 'in_progress'::answer_status
            ELSE 'not_started'::answer_status
        END AS review_status
    FROM assignment_assignees aa
    JOIN users u ON u.id = aa.student_id
    LEFT JOIN selected_questions sq
        ON sq.student_id = aa.student_id
    LEFT JOIN student_answers sa
        ON sa.assignment_id = aa.assignment_id
       AND sa.question_id = sq.question_id
       AND sa.student_id = aa.student_id
    WHERE aa.assignment_id = $1
    GROUP BY aa.assignment_id, aa.student_id, aa.next_step_outcome, u.full_name, u.email
)
SELECT
    student_states.assignment_id,
    student_states.student_id,
    student_states.next_step_outcome,
    student_states.student_name,
    student_states.student_email,
    student_states.total_questions,
    student_states.answered_questions,
    student_states.reviewed_questions,
    student_states.submitted_questions,
    student_states.in_progress_questions,
    student_states.review_status,
    student_states.latest_submitted_at,
    student_states.latest_reviewed_at
FROM student_states
WHERE ($2::text = '' OR review_status::text = $2::text)
ORDER BY student_states.student_name ASC, student_states.student_id ASC;
