// The operator community feed. Members only (active subscription required).
// Posts, comments, and likes. Authors can remove their own; admin can remove any.
import { Router } from 'express';
import { ulid } from 'ulid';
import { z } from 'zod';
import { query, queryOne, execute } from '../db/client.js';
import { requireAuth } from '../middleware/auth.js';
import { requireActiveSubscription } from '../middleware/subscription.js';
import { HttpError } from '../middleware/error.js';

const router = Router();
const now = () => Math.floor(Date.now() / 1000);

// Every community route requires an active membership.
router.use(requireAuth, requireActiveSubscription());

function zodFail(err, next) {
  if (err instanceof z.ZodError) {
    return next(new HttpError(400, 'invalid_input', err.issues[0]?.message || 'Invalid input'));
  }
  next(err);
}

// GET /api/community/feed
router.get('/feed', async (req, res, next) => {
  try {
    const limit = Math.min(Number(req.query.limit) || 30, 100);
    const posts = await query(
      `SELECT p.id, p.body, p.pinned, p.created_at,
              u.id AS user_id, u.display_name, u.avatar_url,
              (SELECT COUNT(*) FROM reactions r  WHERE r.post_id  = p.id AND r.kind = 'like') AS like_count,
              (SELECT COUNT(*) FROM comments  c  WHERE c.post_id  = p.id AND c.deleted_at IS NULL) AS comment_count,
              (SELECT COUNT(*) FROM reactions r2 WHERE r2.post_id = p.id AND r2.user_id = ? AND r2.kind = 'like') AS liked_by_me
       FROM posts p JOIN users u ON u.id = p.user_id
       WHERE p.deleted_at IS NULL
       ORDER BY p.pinned DESC, p.created_at DESC
       LIMIT ?`,
      [req.auth.userId, limit]
    );
    res.json({
      posts: posts.map((p) => ({
        ...p,
        like_count: Number(p.like_count),
        comment_count: Number(p.comment_count),
        liked_by_me: Number(p.liked_by_me) > 0,
      })),
    });
  } catch (err) {
    next(err);
  }
});

const postSchema = z.object({ body: z.string().min(1, 'Post cannot be empty').max(5000) });

router.post('/posts', async (req, res, next) => {
  try {
    const { body } = postSchema.parse(req.body);
    const id = ulid();
    await execute(
      `INSERT INTO posts (id, user_id, body, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`,
      [id, req.auth.userId, body, now(), now()]
    );
    res.status(201).json({ id });
  } catch (err) {
    zodFail(err, next);
  }
});

// GET /api/community/posts/:id  (post plus its comments)
router.get('/posts/:id', async (req, res, next) => {
  try {
    const post = await queryOne(
      `SELECT p.id, p.body, p.pinned, p.created_at, u.id AS user_id, u.display_name, u.avatar_url
       FROM posts p JOIN users u ON u.id = p.user_id
       WHERE p.id = ? AND p.deleted_at IS NULL`,
      [req.params.id]
    );
    if (!post) throw new HttpError(404, 'not_found', 'Post not found');
    const comments = await query(
      `SELECT c.id, c.body, c.created_at, u.id AS user_id, u.display_name, u.avatar_url
       FROM comments c JOIN users u ON u.id = c.user_id
       WHERE c.post_id = ? AND c.deleted_at IS NULL
       ORDER BY c.created_at ASC`,
      [req.params.id]
    );
    res.json({ post, comments });
  } catch (err) {
    next(err);
  }
});

const commentSchema = z.object({ body: z.string().min(1, 'Comment cannot be empty').max(3000) });

router.post('/posts/:id/comments', async (req, res, next) => {
  try {
    const { body } = commentSchema.parse(req.body);
    const post = await queryOne(`SELECT id FROM posts WHERE id = ? AND deleted_at IS NULL`, [req.params.id]);
    if (!post) throw new HttpError(404, 'not_found', 'Post not found');
    const id = ulid();
    await execute(
      `INSERT INTO comments (id, post_id, user_id, body, created_at) VALUES (?, ?, ?, ?, ?)`,
      [id, req.params.id, req.auth.userId, body, now()]
    );
    res.status(201).json({ id });
  } catch (err) {
    zodFail(err, next);
  }
});

router.post('/posts/:id/like', async (req, res, next) => {
  try {
    const post = await queryOne(`SELECT id FROM posts WHERE id = ? AND deleted_at IS NULL`, [req.params.id]);
    if (!post) throw new HttpError(404, 'not_found', 'Post not found');
    await execute(
      `INSERT OR IGNORE INTO reactions (id, post_id, user_id, kind, created_at) VALUES (?, ?, ?, 'like', ?)`,
      [ulid(), req.params.id, req.auth.userId, now()]
    );
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

router.delete('/posts/:id/like', async (req, res, next) => {
  try {
    await execute(`DELETE FROM reactions WHERE post_id = ? AND user_id = ? AND kind = 'like'`, [
      req.params.id,
      req.auth.userId,
    ]);
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

// Soft-delete: author or admin only.
router.delete('/posts/:id', async (req, res, next) => {
  try {
    const post = await queryOne(`SELECT user_id FROM posts WHERE id = ? AND deleted_at IS NULL`, [req.params.id]);
    if (!post) throw new HttpError(404, 'not_found', 'Post not found');
    if (post.user_id !== req.auth.userId && req.auth.role !== 'admin') {
      throw new HttpError(403, 'forbidden', 'You can only remove your own post');
    }
    await execute(`UPDATE posts SET deleted_at = ? WHERE id = ?`, [now(), req.params.id]);
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

export default router;
