-- name: ListMessageRecipientsForUser :many
SELECT
    u.id AS user_id,
    u.email AS user_email,
    u.role AS user_role,
    u.full_name AS user_full_name,
    p.preferred_name,
    p.profile_icon_url,
    p.headline
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.id <> $1
  AND u.is_active = TRUE
  AND (
    EXISTS (
        SELECT 1
        FROM classrooms c
        JOIN classroom_students cs ON cs.classroom_id = c.id
        WHERE c.teacher_id = u.id
          AND cs.student_id = $1
    )
    OR EXISTS (
        SELECT 1
        FROM classrooms c
        JOIN classroom_students cs ON cs.classroom_id = c.id
        WHERE c.teacher_id = $1
          AND cs.student_id = u.id
    )
  )
ORDER BY COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC;

-- name: GetMessageRecipientByIDForUser :one
SELECT
    u.id AS user_id,
    u.email AS user_email,
    u.role AS user_role,
    u.full_name AS user_full_name,
    p.preferred_name,
    p.profile_icon_url,
    p.headline
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.id = $2
  AND u.id <> $1
  AND u.is_active = TRUE
  AND (
    EXISTS (
        SELECT 1
        FROM classrooms c
        JOIN classroom_students cs ON cs.classroom_id = c.id
        WHERE c.teacher_id = u.id
          AND cs.student_id = $1
    )
    OR EXISTS (
        SELECT 1
        FROM classrooms c
        JOIN classroom_students cs ON cs.classroom_id = c.id
        WHERE c.teacher_id = $1
          AND cs.student_id = u.id
    )
  )
LIMIT 1;

-- name: ListMessageThreadsForUser :many
SELECT
    t.id AS thread_id,
    t.subject,
    t.created_by_user_id,
    t.created_at AS thread_created_at,
    t.updated_at AS thread_updated_at,
    COALESCE(last_message.id, 0)::bigint AS last_message_id,
    COALESCE(last_message.body, '') AS last_message_body,
    last_message.created_at AS last_message_created_at,
    COALESCE(last_message.sender_user_id, 0)::bigint AS last_message_sender_user_id,
    sender.full_name AS last_message_sender_full_name,
    sender_profile.preferred_name AS last_message_sender_preferred_name,
    sender_profile.profile_icon_url AS last_message_sender_profile_icon_url,
    COALESCE((
        SELECT COUNT(*)::bigint
        FROM messages unread
        WHERE unread.thread_id = t.id
          AND unread.sender_user_id <> $1
          AND (participant.last_read_at IS NULL OR unread.created_at > participant.last_read_at)
    ), 0)::bigint AS unread_count
FROM message_thread_participants participant
JOIN message_threads t ON t.id = participant.thread_id
LEFT JOIN LATERAL (
    SELECT m.id, m.body, m.created_at, m.sender_user_id
    FROM messages m
    WHERE m.thread_id = t.id
    ORDER BY m.created_at DESC, m.id DESC
    LIMIT 1
) AS last_message ON TRUE
LEFT JOIN users sender ON sender.id = last_message.sender_user_id
LEFT JOIN profiles sender_profile ON sender_profile.user_id = sender.id
WHERE participant.user_id = $1
  AND participant.archived_at IS NULL
ORDER BY COALESCE(last_message.created_at, t.updated_at) DESC, t.id DESC;

-- name: ListMessageThreadParticipantsForUser :many
SELECT
    mtp.thread_id,
    u.id AS user_id,
    u.email AS user_email,
    u.role AS user_role,
    u.full_name AS user_full_name,
    p.preferred_name,
    p.profile_icon_url,
    p.headline,
    mtp.joined_at,
    mtp.last_read_at,
    mtp.archived_at
FROM message_thread_participants mtp
JOIN users u ON u.id = mtp.user_id
LEFT JOIN profiles p ON p.user_id = u.id
WHERE mtp.thread_id IN (
    SELECT participant.thread_id
    FROM message_thread_participants participant
    WHERE participant.user_id = $1
      AND participant.archived_at IS NULL
)
ORDER BY mtp.thread_id ASC, COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC;

-- name: GetMessageThreadForUser :one
SELECT
    t.id,
    t.subject,
    t.created_by_user_id,
    t.created_at,
    t.updated_at,
    participant.last_read_at,
    COALESCE((
        SELECT COUNT(*)::bigint
        FROM messages unread
        WHERE unread.thread_id = t.id
          AND unread.sender_user_id <> $2
          AND (participant.last_read_at IS NULL OR unread.created_at > participant.last_read_at)
    ), 0)::bigint AS unread_count
FROM message_threads t
JOIN message_thread_participants participant ON participant.thread_id = t.id
WHERE t.id = $1
  AND participant.user_id = $2
  AND participant.archived_at IS NULL;

-- name: ListMessagesForThreadForUser :many
SELECT
    m.id,
    m.thread_id,
    m.sender_user_id,
    m.body,
    m.created_at,
    m.updated_at,
    sender.email AS sender_email,
    sender.role AS sender_role,
    sender.full_name AS sender_full_name,
    sender_profile.preferred_name AS sender_preferred_name,
    sender_profile.profile_icon_url AS sender_profile_icon_url,
    sender_profile.headline AS sender_headline
FROM messages m
JOIN message_thread_participants participant ON participant.thread_id = m.thread_id
JOIN users sender ON sender.id = m.sender_user_id
LEFT JOIN profiles sender_profile ON sender_profile.user_id = sender.id
WHERE m.thread_id = $1
  AND participant.user_id = $2
  AND participant.archived_at IS NULL
ORDER BY m.created_at ASC, m.id ASC;

-- name: ListParticipantsForThreadForUser :many
SELECT
    mtp.thread_id,
    u.id AS user_id,
    u.email AS user_email,
    u.role AS user_role,
    u.full_name AS user_full_name,
    p.preferred_name,
    p.profile_icon_url,
    p.headline,
    mtp.joined_at,
    mtp.last_read_at,
    mtp.archived_at
FROM message_thread_participants mtp
JOIN users u ON u.id = mtp.user_id
LEFT JOIN profiles p ON p.user_id = u.id
WHERE mtp.thread_id = $1
  AND EXISTS (
    SELECT 1
    FROM message_thread_participants participant
    WHERE participant.thread_id = mtp.thread_id
      AND participant.user_id = $2
      AND participant.archived_at IS NULL
  )
ORDER BY COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC;

-- name: CreateMessageThread :one
INSERT INTO message_threads (
    created_by_user_id,
    subject
) VALUES (
    $1,
    $2
)
RETURNING *;

-- name: AddMessageThreadParticipant :exec
INSERT INTO message_thread_participants (
    thread_id,
    user_id,
    last_read_at
) VALUES (
    $1,
    $2,
    $3
)
ON CONFLICT (thread_id, user_id) DO NOTHING;

-- name: CreateThreadMessage :one
INSERT INTO messages (
    thread_id,
    sender_user_id,
    body
) VALUES (
    $1,
    $2,
    $3
)
RETURNING *;

-- name: TouchMessageThread :exec
UPDATE message_threads
SET updated_at = NOW()
WHERE id = $1;

-- name: UpdateMessageThreadSubject :one
UPDATE message_threads
SET subject = sqlc.arg(subject),
    updated_at = NOW()
WHERE id = sqlc.arg(thread_id)
RETURNING *;

-- name: UpdateThreadMessageBody :one
UPDATE messages
SET body = sqlc.arg(body),
    updated_at = NOW()
WHERE id = sqlc.arg(message_id)
  AND thread_id = sqlc.arg(thread_id)
  AND sender_user_id = sqlc.arg(user_id)
RETURNING *;

-- name: DeleteThreadMessage :one
DELETE FROM messages
WHERE id = sqlc.arg(message_id)
  AND thread_id = sqlc.arg(thread_id)
  AND sender_user_id = sqlc.arg(user_id)
RETURNING *;

-- name: DeleteMessageThread :one
DELETE FROM message_threads
WHERE id = sqlc.arg(thread_id)
RETURNING *;

-- name: MarkMessageThreadRead :one
UPDATE message_thread_participants
SET last_read_at = COALESCE((SELECT MAX(m.created_at) FROM messages m WHERE m.thread_id = $1), NOW())
WHERE message_thread_participants.thread_id = $1
  AND message_thread_participants.user_id = $2
RETURNING *;
