// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.30.0
// source: assignments.sql

package sqlc

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
)

const addAssignmentStudentQuestion = `-- 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 id, assignment_id, student_id, question_id, position, source_bucket, source_topic, source_difficulty, generator_seed, created_at
`

type AddAssignmentStudentQuestionParams struct {
	AssignmentID     int64                  `json:"assignment_id"`
	StudentID        int64                  `json:"student_id"`
	QuestionID       int64                  `json:"question_id"`
	Position         int32                  `json:"position"`
	SourceBucket     string                 `json:"source_bucket"`
	SourceTopic      NullQuestionTopic      `json:"source_topic"`
	SourceDifficulty NullQuestionDifficulty `json:"source_difficulty"`
	GeneratorSeed    pgtype.Int8            `json:"generator_seed"`
}

func (q *Queries) AddAssignmentStudentQuestion(ctx context.Context, arg AddAssignmentStudentQuestionParams) (AssignmentStudentQuestion, error) {
	row := q.db.QueryRow(ctx, addAssignmentStudentQuestion,
		arg.AssignmentID,
		arg.StudentID,
		arg.QuestionID,
		arg.Position,
		arg.SourceBucket,
		arg.SourceTopic,
		arg.SourceDifficulty,
		arg.GeneratorSeed,
	)
	var i AssignmentStudentQuestion
	err := row.Scan(
		&i.ID,
		&i.AssignmentID,
		&i.StudentID,
		&i.QuestionID,
		&i.Position,
		&i.SourceBucket,
		&i.SourceTopic,
		&i.SourceDifficulty,
		&i.GeneratorSeed,
		&i.CreatedAt,
	)
	return i, err
}

const addQuestionToAssignment = `-- 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
`

type AddQuestionToAssignmentParams struct {
	AssignmentID int64 `json:"assignment_id"`
	QuestionID   int64 `json:"question_id"`
	Position     int32 `json:"position"`
}

func (q *Queries) AddQuestionToAssignment(ctx context.Context, arg AddQuestionToAssignmentParams) error {
	_, err := q.db.Exec(ctx, addQuestionToAssignment, arg.AssignmentID, arg.QuestionID, arg.Position)
	return err
}

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

type AssignStudentToAssignmentParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

func (q *Queries) AssignStudentToAssignment(ctx context.Context, arg AssignStudentToAssignmentParams) error {
	_, err := q.db.Exec(ctx, assignStudentToAssignment, arg.AssignmentID, arg.StudentID)
	return err
}

const closeAssignment = `-- name: CloseAssignment :one
UPDATE assignments
SET status = 'closed'::assignment_status,
    updated_at = NOW()
WHERE id = $1
RETURNING id, classroom_id, teacher_id, title, instructions, status, due_at, published_at, created_at, updated_at, pass_threshold
`

func (q *Queries) CloseAssignment(ctx context.Context, id int64) (Assignment, error) {
	row := q.db.QueryRow(ctx, closeAssignment, id)
	var i Assignment
	err := row.Scan(
		&i.ID,
		&i.ClassroomID,
		&i.TeacherID,
		&i.Title,
		&i.Instructions,
		&i.Status,
		&i.DueAt,
		&i.PublishedAt,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PassThreshold,
	)
	return i, err
}

const createAssignment = `-- 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 id, classroom_id, teacher_id, title, instructions, status, due_at, published_at, created_at, updated_at, pass_threshold
`

type CreateAssignmentParams struct {
	ClassroomID   int64              `json:"classroom_id"`
	TeacherID     int64              `json:"teacher_id"`
	Title         string             `json:"title"`
	Instructions  pgtype.Text        `json:"instructions"`
	Status        AssignmentStatus   `json:"status"`
	DueAt         pgtype.Timestamptz `json:"due_at"`
	PublishedAt   pgtype.Timestamptz `json:"published_at"`
	PassThreshold pgtype.Numeric     `json:"pass_threshold"`
}

func (q *Queries) CreateAssignment(ctx context.Context, arg CreateAssignmentParams) (Assignment, error) {
	row := q.db.QueryRow(ctx, createAssignment,
		arg.ClassroomID,
		arg.TeacherID,
		arg.Title,
		arg.Instructions,
		arg.Status,
		arg.DueAt,
		arg.PublishedAt,
		arg.PassThreshold,
	)
	var i Assignment
	err := row.Scan(
		&i.ID,
		&i.ClassroomID,
		&i.TeacherID,
		&i.Title,
		&i.Instructions,
		&i.Status,
		&i.DueAt,
		&i.PublishedAt,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PassThreshold,
	)
	return i, err
}

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

type DeleteAssignmentAssigneeParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

func (q *Queries) DeleteAssignmentAssignee(ctx context.Context, arg DeleteAssignmentAssigneeParams) error {
	_, err := q.db.Exec(ctx, deleteAssignmentAssignee, arg.AssignmentID, arg.StudentID)
	return err
}

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

type DeleteAssignmentStudentQuestionsParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

func (q *Queries) DeleteAssignmentStudentQuestions(ctx context.Context, arg DeleteAssignmentStudentQuestionsParams) error {
	_, err := q.db.Exec(ctx, deleteAssignmentStudentQuestions, arg.AssignmentID, arg.StudentID)
	return err
}

const getAssignmentAssignee = `-- name: GetAssignmentAssignee :one
SELECT assignment_id, student_id, assigned_at, ai_feedback, teacher_feedback, overall_score, pass_threshold, pass_status, pass_status_override, next_step_outcome, redo_plan, redo_plan_generated_at
FROM assignment_assignees
WHERE assignment_id = $1
  AND student_id = $2
`

type GetAssignmentAssigneeParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

func (q *Queries) GetAssignmentAssignee(ctx context.Context, arg GetAssignmentAssigneeParams) (AssignmentAssignee, error) {
	row := q.db.QueryRow(ctx, getAssignmentAssignee, arg.AssignmentID, arg.StudentID)
	var i AssignmentAssignee
	err := row.Scan(
		&i.AssignmentID,
		&i.StudentID,
		&i.AssignedAt,
		&i.AiFeedback,
		&i.TeacherFeedback,
		&i.OverallScore,
		&i.PassThreshold,
		&i.PassStatus,
		&i.PassStatusOverride,
		&i.NextStepOutcome,
		&i.RedoPlan,
		&i.RedoPlanGeneratedAt,
	)
	return i, err
}

const getAssignmentByID = `-- name: GetAssignmentByID :one
SELECT id, classroom_id, teacher_id, title, instructions, status, due_at, published_at, created_at, updated_at, pass_threshold
FROM assignments
WHERE id = $1
`

func (q *Queries) GetAssignmentByID(ctx context.Context, id int64) (Assignment, error) {
	row := q.db.QueryRow(ctx, getAssignmentByID, id)
	var i Assignment
	err := row.Scan(
		&i.ID,
		&i.ClassroomID,
		&i.TeacherID,
		&i.Title,
		&i.Instructions,
		&i.Status,
		&i.DueAt,
		&i.PublishedAt,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PassThreshold,
	)
	return i, err
}

const getAssignmentRedoPlan = `-- 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
`

type GetAssignmentRedoPlanParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

type GetAssignmentRedoPlanRow struct {
	AssignmentID        int64              `json:"assignment_id"`
	StudentID           int64              `json:"student_id"`
	RedoPlan            pgtype.Text        `json:"redo_plan"`
	RedoPlanGeneratedAt pgtype.Timestamptz `json:"redo_plan_generated_at"`
}

func (q *Queries) GetAssignmentRedoPlan(ctx context.Context, arg GetAssignmentRedoPlanParams) (GetAssignmentRedoPlanRow, error) {
	row := q.db.QueryRow(ctx, getAssignmentRedoPlan, arg.AssignmentID, arg.StudentID)
	var i GetAssignmentRedoPlanRow
	err := row.Scan(
		&i.AssignmentID,
		&i.StudentID,
		&i.RedoPlan,
		&i.RedoPlanGeneratedAt,
	)
	return i, err
}

const getAssignmentReviewSummary = `-- 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
`

type GetAssignmentReviewSummaryRow struct {
	AssignmentID   int64 `json:"assignment_id"`
	TotalQuestions int64 `json:"total_questions"`
	TotalAssigned  int64 `json:"total_assigned"`
	NotStarted     int64 `json:"not_started"`
	InProgress     int64 `json:"in_progress"`
	Submitted      int64 `json:"submitted"`
	Reviewed       int64 `json:"reviewed"`
}

func (q *Queries) GetAssignmentReviewSummary(ctx context.Context, dollar_1 int64) (GetAssignmentReviewSummaryRow, error) {
	row := q.db.QueryRow(ctx, getAssignmentReviewSummary, dollar_1)
	var i GetAssignmentReviewSummaryRow
	err := row.Scan(
		&i.AssignmentID,
		&i.TotalQuestions,
		&i.TotalAssigned,
		&i.NotStarted,
		&i.InProgress,
		&i.Submitted,
		&i.Reviewed,
	)
	return i, err
}

const listAssignmentReviewQueue = `-- 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
`

type ListAssignmentReviewQueueParams struct {
	AssignmentID int64  `json:"assignment_id"`
	Column2      string `json:"column_2"`
}

type ListAssignmentReviewQueueRow struct {
	AssignmentID        int64                         `json:"assignment_id"`
	StudentID           int64                         `json:"student_id"`
	NextStepOutcome     NullAssignmentNextStepOutcome `json:"next_step_outcome"`
	StudentName         string                        `json:"student_name"`
	StudentEmail        string                        `json:"student_email"`
	TotalQuestions      int64                         `json:"total_questions"`
	AnsweredQuestions   int64                         `json:"answered_questions"`
	ReviewedQuestions   int64                         `json:"reviewed_questions"`
	SubmittedQuestions  int64                         `json:"submitted_questions"`
	InProgressQuestions int64                         `json:"in_progress_questions"`
	ReviewStatus        AnswerStatus                  `json:"review_status"`
	LatestSubmittedAt   pgtype.Timestamptz            `json:"latest_submitted_at"`
	LatestReviewedAt    pgtype.Timestamptz            `json:"latest_reviewed_at"`
}

func (q *Queries) ListAssignmentReviewQueue(ctx context.Context, arg ListAssignmentReviewQueueParams) ([]ListAssignmentReviewQueueRow, error) {
	rows, err := q.db.Query(ctx, listAssignmentReviewQueue, arg.AssignmentID, arg.Column2)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListAssignmentReviewQueueRow{}
	for rows.Next() {
		var i ListAssignmentReviewQueueRow
		if err := rows.Scan(
			&i.AssignmentID,
			&i.StudentID,
			&i.NextStepOutcome,
			&i.StudentName,
			&i.StudentEmail,
			&i.TotalQuestions,
			&i.AnsweredQuestions,
			&i.ReviewedQuestions,
			&i.SubmittedQuestions,
			&i.InProgressQuestions,
			&i.ReviewStatus,
			&i.LatestSubmittedAt,
			&i.LatestReviewedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listAssignmentStudentQuestions = `-- name: ListAssignmentStudentQuestions :many
SELECT id, assignment_id, student_id, question_id, position, source_bucket, source_topic, source_difficulty, generator_seed, created_at
FROM assignment_student_questions
WHERE assignment_id = $1
  AND student_id = $2
ORDER BY position ASC, id ASC
`

type ListAssignmentStudentQuestionsParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

func (q *Queries) ListAssignmentStudentQuestions(ctx context.Context, arg ListAssignmentStudentQuestionsParams) ([]AssignmentStudentQuestion, error) {
	rows, err := q.db.Query(ctx, listAssignmentStudentQuestions, arg.AssignmentID, arg.StudentID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []AssignmentStudentQuestion{}
	for rows.Next() {
		var i AssignmentStudentQuestion
		if err := rows.Scan(
			&i.ID,
			&i.AssignmentID,
			&i.StudentID,
			&i.QuestionID,
			&i.Position,
			&i.SourceBucket,
			&i.SourceTopic,
			&i.SourceDifficulty,
			&i.GeneratorSeed,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listAssignmentsByTeacher = `-- name: ListAssignmentsByTeacher :many
SELECT id, classroom_id, teacher_id, title, instructions, status, due_at, published_at, created_at, updated_at, pass_threshold
FROM assignments
WHERE teacher_id = $1
ORDER BY created_at DESC
`

func (q *Queries) ListAssignmentsByTeacher(ctx context.Context, teacherID int64) ([]Assignment, error) {
	rows, err := q.db.Query(ctx, listAssignmentsByTeacher, teacherID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Assignment{}
	for rows.Next() {
		var i Assignment
		if err := rows.Scan(
			&i.ID,
			&i.ClassroomID,
			&i.TeacherID,
			&i.Title,
			&i.Instructions,
			&i.Status,
			&i.DueAt,
			&i.PublishedAt,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.PassThreshold,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listAssignmentsForStudent = `-- name: ListAssignmentsForStudent :many
SELECT a.id, a.classroom_id, a.teacher_id, a.title, a.instructions, a.status, a.due_at, a.published_at, a.created_at, a.updated_at, a.pass_threshold
FROM assignment_assignees aa
JOIN assignments a ON a.id = aa.assignment_id
WHERE aa.student_id = $1
ORDER BY a.created_at DESC
`

func (q *Queries) ListAssignmentsForStudent(ctx context.Context, studentID int64) ([]Assignment, error) {
	rows, err := q.db.Query(ctx, listAssignmentsForStudent, studentID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Assignment{}
	for rows.Next() {
		var i Assignment
		if err := rows.Scan(
			&i.ID,
			&i.ClassroomID,
			&i.TeacherID,
			&i.Title,
			&i.Instructions,
			&i.Status,
			&i.DueAt,
			&i.PublishedAt,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.PassThreshold,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listGeneratedQuestionsForAssignmentStudent = `-- 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
`

type ListGeneratedQuestionsForAssignmentStudentParams struct {
	AssignmentID int64 `json:"assignment_id"`
	StudentID    int64 `json:"student_id"`
}

type ListGeneratedQuestionsForAssignmentStudentRow struct {
	ID                int64                  `json:"id"`
	AssignmentID      int64                  `json:"assignment_id"`
	StudentID         int64                  `json:"student_id"`
	QuestionID        int64                  `json:"question_id"`
	Position          int32                  `json:"position"`
	SourceBucket      string                 `json:"source_bucket"`
	SourceTopic       NullQuestionTopic      `json:"source_topic"`
	SourceDifficulty  NullQuestionDifficulty `json:"source_difficulty"`
	GeneratorSeed     pgtype.Int8            `json:"generator_seed"`
	CreatedAt         pgtype.Timestamptz     `json:"created_at"`
	AuthorTeacherID   int64                  `json:"author_teacher_id"`
	Title             string                 `json:"title"`
	Prompt            string                 `json:"prompt"`
	Subject           pgtype.Text            `json:"subject"`
	Source            pgtype.Text            `json:"source"`
	Status            QuestionStatus         `json:"status"`
	QuestionCreatedAt pgtype.Timestamptz     `json:"question_created_at"`
	QuestionUpdatedAt pgtype.Timestamptz     `json:"question_updated_at"`
	CorrectAnswer     pgtype.Text            `json:"correct_answer"`
	Topic             NullQuestionTopic      `json:"topic"`
	Difficulty        NullQuestionDifficulty `json:"difficulty"`
}

func (q *Queries) ListGeneratedQuestionsForAssignmentStudent(ctx context.Context, arg ListGeneratedQuestionsForAssignmentStudentParams) ([]ListGeneratedQuestionsForAssignmentStudentRow, error) {
	rows, err := q.db.Query(ctx, listGeneratedQuestionsForAssignmentStudent, arg.AssignmentID, arg.StudentID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListGeneratedQuestionsForAssignmentStudentRow{}
	for rows.Next() {
		var i ListGeneratedQuestionsForAssignmentStudentRow
		if err := rows.Scan(
			&i.ID,
			&i.AssignmentID,
			&i.StudentID,
			&i.QuestionID,
			&i.Position,
			&i.SourceBucket,
			&i.SourceTopic,
			&i.SourceDifficulty,
			&i.GeneratorSeed,
			&i.CreatedAt,
			&i.AuthorTeacherID,
			&i.Title,
			&i.Prompt,
			&i.Subject,
			&i.Source,
			&i.Status,
			&i.QuestionCreatedAt,
			&i.QuestionUpdatedAt,
			&i.CorrectAnswer,
			&i.Topic,
			&i.Difficulty,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listQuestionsForAssignment = `-- 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
`

type ListQuestionsForAssignmentRow struct {
	AssignmentID    int64              `json:"assignment_id"`
	QuestionID      int64              `json:"question_id"`
	Position        int32              `json:"position"`
	AuthorTeacherID int64              `json:"author_teacher_id"`
	Title           string             `json:"title"`
	Prompt          string             `json:"prompt"`
	Subject         pgtype.Text        `json:"subject"`
	Source          pgtype.Text        `json:"source"`
	Status          QuestionStatus     `json:"status"`
	CreatedAt       pgtype.Timestamptz `json:"created_at"`
	UpdatedAt       pgtype.Timestamptz `json:"updated_at"`
}

func (q *Queries) ListQuestionsForAssignment(ctx context.Context, assignmentID int64) ([]ListQuestionsForAssignmentRow, error) {
	rows, err := q.db.Query(ctx, listQuestionsForAssignment, assignmentID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListQuestionsForAssignmentRow{}
	for rows.Next() {
		var i ListQuestionsForAssignmentRow
		if err := rows.Scan(
			&i.AssignmentID,
			&i.QuestionID,
			&i.Position,
			&i.AuthorTeacherID,
			&i.Title,
			&i.Prompt,
			&i.Subject,
			&i.Source,
			&i.Status,
			&i.CreatedAt,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const updateAssignmentAIReview = `-- 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 assignment_id, student_id, assigned_at, ai_feedback, teacher_feedback, overall_score, pass_threshold, pass_status, pass_status_override, next_step_outcome, redo_plan, redo_plan_generated_at
`

type UpdateAssignmentAIReviewParams struct {
	AssignmentID int64       `json:"assignment_id"`
	StudentID    int64       `json:"student_id"`
	AiFeedback   pgtype.Text `json:"ai_feedback"`
	Column4      string      `json:"column_4"`
}

func (q *Queries) UpdateAssignmentAIReview(ctx context.Context, arg UpdateAssignmentAIReviewParams) (AssignmentAssignee, error) {
	row := q.db.QueryRow(ctx, updateAssignmentAIReview,
		arg.AssignmentID,
		arg.StudentID,
		arg.AiFeedback,
		arg.Column4,
	)
	var i AssignmentAssignee
	err := row.Scan(
		&i.AssignmentID,
		&i.StudentID,
		&i.AssignedAt,
		&i.AiFeedback,
		&i.TeacherFeedback,
		&i.OverallScore,
		&i.PassThreshold,
		&i.PassStatus,
		&i.PassStatusOverride,
		&i.NextStepOutcome,
		&i.RedoPlan,
		&i.RedoPlanGeneratedAt,
	)
	return i, err
}

const updateAssignmentDraft = `-- 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 id, classroom_id, teacher_id, title, instructions, status, due_at, published_at, created_at, updated_at, pass_threshold
`

type UpdateAssignmentDraftParams struct {
	ID            int64              `json:"id"`
	ClassroomID   int64              `json:"classroom_id"`
	Title         string             `json:"title"`
	Instructions  pgtype.Text        `json:"instructions"`
	DueAt         pgtype.Timestamptz `json:"due_at"`
	PassThreshold pgtype.Numeric     `json:"pass_threshold"`
}

func (q *Queries) UpdateAssignmentDraft(ctx context.Context, arg UpdateAssignmentDraftParams) (Assignment, error) {
	row := q.db.QueryRow(ctx, updateAssignmentDraft,
		arg.ID,
		arg.ClassroomID,
		arg.Title,
		arg.Instructions,
		arg.DueAt,
		arg.PassThreshold,
	)
	var i Assignment
	err := row.Scan(
		&i.ID,
		&i.ClassroomID,
		&i.TeacherID,
		&i.Title,
		&i.Instructions,
		&i.Status,
		&i.DueAt,
		&i.PublishedAt,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PassThreshold,
	)
	return i, err
}

const updateAssignmentRedoPlan = `-- 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 assignment_id, student_id, assigned_at, ai_feedback, teacher_feedback, overall_score, pass_threshold, pass_status, pass_status_override, next_step_outcome, redo_plan, redo_plan_generated_at
`

type UpdateAssignmentRedoPlanParams struct {
	AssignmentID int64  `json:"assignment_id"`
	StudentID    int64  `json:"student_id"`
	Column3      string `json:"column_3"`
}

func (q *Queries) UpdateAssignmentRedoPlan(ctx context.Context, arg UpdateAssignmentRedoPlanParams) (AssignmentAssignee, error) {
	row := q.db.QueryRow(ctx, updateAssignmentRedoPlan, arg.AssignmentID, arg.StudentID, arg.Column3)
	var i AssignmentAssignee
	err := row.Scan(
		&i.AssignmentID,
		&i.StudentID,
		&i.AssignedAt,
		&i.AiFeedback,
		&i.TeacherFeedback,
		&i.OverallScore,
		&i.PassThreshold,
		&i.PassStatus,
		&i.PassStatusOverride,
		&i.NextStepOutcome,
		&i.RedoPlan,
		&i.RedoPlanGeneratedAt,
	)
	return i, err
}

const updateAssignmentTeacherFeedback = `-- 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.assignment_id, aa.student_id, aa.assigned_at, aa.ai_feedback, aa.teacher_feedback, aa.overall_score, aa.pass_threshold, aa.pass_status, aa.pass_status_override, aa.next_step_outcome, aa.redo_plan, aa.redo_plan_generated_at
)
SELECT assignment_id, student_id, assigned_at, ai_feedback, teacher_feedback, overall_score, pass_threshold, pass_status, pass_status_override, next_step_outcome, redo_plan, redo_plan_generated_at
FROM updated
`

type UpdateAssignmentTeacherFeedbackParams struct {
	AssignmentID    int64       `json:"assignment_id"`
	StudentID       int64       `json:"student_id"`
	TeacherFeedback pgtype.Text `json:"teacher_feedback"`
	Column4         string      `json:"column_4"`
	Column5         string      `json:"column_5"`
}

type UpdateAssignmentTeacherFeedbackRow struct {
	AssignmentID        int64                         `json:"assignment_id"`
	StudentID           int64                         `json:"student_id"`
	AssignedAt          pgtype.Timestamptz            `json:"assigned_at"`
	AiFeedback          pgtype.Text                   `json:"ai_feedback"`
	TeacherFeedback     pgtype.Text                   `json:"teacher_feedback"`
	OverallScore        pgtype.Numeric                `json:"overall_score"`
	PassThreshold       pgtype.Numeric                `json:"pass_threshold"`
	PassStatus          AssignmentPassStatus          `json:"pass_status"`
	PassStatusOverride  NullAssignmentPassStatus      `json:"pass_status_override"`
	NextStepOutcome     NullAssignmentNextStepOutcome `json:"next_step_outcome"`
	RedoPlan            pgtype.Text                   `json:"redo_plan"`
	RedoPlanGeneratedAt pgtype.Timestamptz            `json:"redo_plan_generated_at"`
}

func (q *Queries) UpdateAssignmentTeacherFeedback(ctx context.Context, arg UpdateAssignmentTeacherFeedbackParams) (UpdateAssignmentTeacherFeedbackRow, error) {
	row := q.db.QueryRow(ctx, updateAssignmentTeacherFeedback,
		arg.AssignmentID,
		arg.StudentID,
		arg.TeacherFeedback,
		arg.Column4,
		arg.Column5,
	)
	var i UpdateAssignmentTeacherFeedbackRow
	err := row.Scan(
		&i.AssignmentID,
		&i.StudentID,
		&i.AssignedAt,
		&i.AiFeedback,
		&i.TeacherFeedback,
		&i.OverallScore,
		&i.PassThreshold,
		&i.PassStatus,
		&i.PassStatusOverride,
		&i.NextStepOutcome,
		&i.RedoPlan,
		&i.RedoPlanGeneratedAt,
	)
	return i, err
}
