import type { Request } from "express";
import { one, query } from "../../db/client.js";
import { audit } from "../../lib/audit.js";
import { forbidden, notFound } from "../../lib/errors.js";

/** Social v1: publisher posts notify all active accounts; author/moderator may remove. */

export async function hasPublishRight(userId: number): Promise<boolean> {
  const r = await one<{ n: number }>(
    `SELECT COUNT(*)::int AS n
       FROM user_roles ur
       JOIN role_permissions rp ON rp.role_id = ur.role_id
       JOIN permissions p ON p.id = rp.permission_id AND p.code = 'social.publish'
      WHERE ur.user_id = $1 AND ur.revoked_at IS NULL
        AND (ur.valid_until IS NULL OR ur.valid_until > now())`,
    [userId],
  );
  return !!r && r.n > 0;
}

export async function createPost(req: Request, body: string): Promise<{ id: number }> {
  const row = await one<{ id: number }>(
    `INSERT INTO social_posts (author_id, body) VALUES ($1, $2) RETURNING id`,
    [req.user!.id, body.trim()],
  );
  // notify every other active account
  await query(
    `INSERT INTO notifications (user_id, type, title_ar, body_ar, link)
     SELECT id, 'post', 'منشور جديد من ' || $3, LEFT($2, 140), '/dashboard/social'
       FROM users WHERE is_active AND id <> $1`,
    [req.user!.id, body.trim().slice(0, 140), req.user!.fullName],
  );
  await audit({
    actorUserId: req.user!.id,
    action: "social.post_created",
    entityType: "social_post",
    entityId: row!.id,
    changedFields: { length: body.trim().length },
    ip: req.ip ?? null,
    userAgent: req.headers["user-agent"] ?? null,
  });
  return { id: row!.id };
}

export async function listPosts(page: number): Promise<{ items: unknown[]; total: number }> {
  const pageSize = 20;
  const items = (
    await query(
      `SELECT p.id, p.body, p.created_at::text, u.full_name AS author_name, u.username AS author_username
         FROM social_posts p JOIN users u ON u.id = p.author_id
        WHERE p.status = 'published'
        ORDER BY p.created_at DESC
        LIMIT $1 OFFSET $2`,
      [pageSize, (page - 1) * pageSize],
    )
  ).rows;
  const total = Number(
    (await one<{ count: string }>(`SELECT COUNT(*)::text AS count FROM social_posts WHERE status = 'published'`))?.count ?? 0,
  );
  return { items, total };
}

export async function removePost(req: Request, id: number, reason: string): Promise<void> {
  const post = await one<{ id: number; author_id: number; status: string }>(`SELECT id, author_id, status FROM social_posts WHERE id = $1`, [id]);
  if (!post || post.status !== "published") throw notFound("المنشور غير موجود أو مُزال بالفعل");
  const canModerate = await hasPublishRight(req.user!.id);
  if (!canModerate && post.author_id !== req.user!.id) {
    throw forbidden("الإزالة لصاحب المنشور أو لمن يملك حق النشر");
  }
  await query(
    `UPDATE social_posts SET status = 'removed', removed_by = $2, removal_reason = $3, removed_at = now() WHERE id = $1`,
    [id, req.user!.id, reason.trim()],
  );
  await audit({
    actorUserId: req.user!.id,
    action: "social.post_removed",
    entityType: "social_post",
    entityId: id,
    context: { reason: reason.trim(), byAuthor: post.author_id === req.user!.id },
    ip: req.ip ?? null,
    userAgent: req.headers["user-agent"] ?? null,
  });
}

export async function myNotifications(userId: number): Promise<{ items: unknown[]; unread: number }> {
  const items = (
    await query(
      `SELECT id, type, title_ar, body_ar, link, read_at::text, created_at::text
         FROM notifications WHERE user_id = $1 ORDER BY created_at DESC LIMIT 50`,
      [userId],
    )
  ).rows;
  const unread = Number(
    (await one<{ count: string }>(`SELECT COUNT(*)::text AS count FROM notifications WHERE user_id = $1 AND read_at IS NULL`, [userId]))?.count ?? 0,
  );
  return { items, unread };
}

export async function markNotificationsRead(userId: number, id?: number): Promise<void> {
  if (id) await query(`UPDATE notifications SET read_at = now() WHERE user_id = $1 AND id = $2 AND read_at IS NULL`, [userId, id]);
  else await query(`UPDATE notifications SET read_at = now() WHERE user_id = $1 AND read_at IS NULL`, [userId]);
}
