-- name: CreatePost :exec
INSERT INTO posts (
  id, parent_id, author_id, title, body, city, post_date, hidden, created_at, updated_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);

-- name: GetPost :one
SELECT
  p.id, p.parent_id, p.author_id, u.name AS author_name, u.role AS author_role,
  p.title, p.body, p.city, p.post_date, p.hidden, p.created_at, p.updated_at
FROM posts p
JOIN users u ON u.id = p.author_id
WHERE p.id = $1;

-- name: ListPostThread :many
WITH RECURSIVE thread AS (
  SELECT p.*
  FROM posts p
  WHERE p.id = $1 AND p.parent_id IS NULL

  UNION ALL

  SELECT child.*
  FROM posts child
  JOIN thread parent ON child.parent_id = parent.id
)
SELECT
  thread.id, thread.parent_id, thread.author_id,
  u.name AS author_name, u.role AS author_role,
  thread.title, thread.body, thread.city, thread.post_date,
  thread.hidden, thread.created_at, thread.updated_at
FROM thread
JOIN users u ON u.id = thread.author_id
ORDER BY thread.created_at, thread.id;

-- name: UpdatePost :execrows
UPDATE posts
SET body = $2, updated_at = $3
WHERE id = $1;

-- name: ListRootPosts :many
WITH RECURSIVE roots AS (
  SELECT p.*
  FROM posts p
  WHERE p.parent_id IS NULL
    AND p.post_date = sqlc.arg(post_date)
    AND p.hidden = 0
),
thread AS (
  SELECT roots.id AS root_id, roots.id AS post_id, roots.author_id
  FROM roots

  UNION ALL

  SELECT thread.root_id, child.id, child.author_id
  FROM thread
  JOIN posts child ON child.parent_id = thread.post_id
),
answered AS (
  SELECT thread.root_id, bool_or(u.role = 'admin' AND thread.post_id <> thread.root_id) AS answered
  FROM thread
  JOIN users u ON u.id = thread.author_id
  GROUP BY thread.root_id
),
scores AS (
  SELECT post_id, COALESCE(SUM(value), 0)::bigint AS score
  FROM post_votes
  GROUP BY post_id
)
SELECT
  roots.id, roots.parent_id, roots.author_id,
  u.name AS author_name, u.role AS author_role,
  roots.title, roots.body, roots.city, roots.post_date,
  roots.hidden, roots.created_at, roots.updated_at,
  COALESCE(scores.score, 0)::bigint AS score,
  COALESCE(answered.answered, false)::bool AS answered,
  COALESCE((
    SELECT post_votes.value
    FROM post_votes
    WHERE post_votes.user_id = sqlc.arg(viewer_id)
      AND post_votes.post_id = roots.id
  ), 0)::bigint AS user_vote
FROM roots
JOIN users u ON u.id = roots.author_id
LEFT JOIN scores ON scores.post_id = roots.id
LEFT JOIN answered ON answered.root_id = roots.id
ORDER BY score DESC, roots.created_at, roots.id
LIMIT sqlc.arg(row_limit);

-- name: PostIsVisibleRoot :one
SELECT EXISTS(
  SELECT 1
  FROM posts
  WHERE id = $1 AND parent_id IS NULL AND hidden = 0
)::bool;

-- name: DeletePostVote :exec
DELETE FROM post_votes
WHERE user_id = $1 AND post_id = $2;

-- name: UpsertPostVoteOnVisibleRoot :execrows
INSERT INTO post_votes (user_id, post_id, value)
SELECT $1, $2, $3
FROM posts p
WHERE p.id = $2 AND p.parent_id IS NULL AND p.hidden = 0
ON CONFLICT (user_id, post_id) DO UPDATE
SET value = excluded.value
WHERE EXISTS (
  SELECT 1
  FROM posts p2
  WHERE p2.id = excluded.post_id AND p2.parent_id IS NULL AND p2.hidden = 0
);
