import type { CurrentUser, Env } from '../env';
import { all, first } from '../db/queries';
import { escapeHtml } from '../utils/html';
import { nowSeconds } from '../utils/time';
import { ulid } from '../utils/id';

export interface CommentView {
  id: string;
  postId: string;
  parentId: string | null;
  authorName: string;
  authorUrl: string | null;
  avatarKey: string | null;
  replyToName: string | null;
  content: string;
  contentHtml: string;
  status: 'approved' | 'pending' | 'spam' | 'trash';
  createdAt: number;
  canDelete: boolean;
}

interface CommentJoinedRow {
  id: string;
  post_id: string;
  parent_id: string | null;
  user_id: string | null;
  guest_name: string | null;
  guest_url: string | null;
  content: string;
  status: 'approved' | 'pending' | 'spam' | 'trash';
  created_at: number;
  username: string | null;
  display_name: string | null;
  avatar_key: string | null;
  parent_user_display_name: string | null;
  parent_guest_name: string | null;
  post_author_id: string;
}

function mapComment(row: CommentJoinedRow, viewer?: CurrentUser | null): CommentView {
  const authorName = row.display_name || row.guest_name || '访客';
  return {
    id: row.id,
    postId: row.post_id,
    parentId: row.parent_id,
    authorName,
    authorUrl: row.username ? `/u/${row.username}` : row.guest_url,
    avatarKey: row.avatar_key,
    replyToName: row.parent_user_display_name || row.parent_guest_name || null,
    content: row.content,
    contentHtml: escapeHtml(row.content).replace(/\n/g, '<br>'),
    status: row.status,
    createdAt: row.created_at,
    canDelete: Boolean(viewer && (viewer.role === 'admin' || viewer.id === row.user_id || viewer.id === row.post_author_id))
  };
}

export async function listComments(env: Env['Bindings'], postId: string, viewer?: CurrentUser | null): Promise<CommentView[]> {
  const rows = await all<CommentJoinedRow>(
    env.DB.prepare(
      `SELECT c.*, u.username, u.display_name, u.avatar_key,
        pu.display_name AS parent_user_display_name, pc.guest_name AS parent_guest_name,
        p.author_id AS post_author_id
       FROM wm_comments c
       JOIN wm_posts p ON p.id = c.post_id
       LEFT JOIN wm_users u ON u.id = c.user_id
       LEFT JOIN wm_comments pc ON pc.id = c.parent_id
       LEFT JOIN wm_users pu ON pu.id = pc.user_id
       WHERE c.post_id = ? AND c.status = 'approved'
       ORDER BY c.created_at ASC`
    ).bind(postId)
  );
  return rows.map((row) => mapComment(row, viewer));
}

export async function createComment(
  env: Env['Bindings'],
  input: {
    postId: string;
    parentId?: string | null;
    content: string;
    guestName?: string | null;
    guestEmail?: string | null;
    guestUrl?: string | null;
    status: 'approved' | 'pending';
    user?: CurrentUser | null;
    ip?: string | null;
    userAgent?: string | null;
  }
): Promise<string> {
  const post = await first<{ id: string }>(
    env.DB.prepare(`SELECT id FROM wm_posts WHERE id = ? AND status = 'published'`).bind(input.postId)
  );
  if (!post) throw new Error('内容不存在');
  if (input.parentId) {
    const parent = await first<{ id: string }>(
      env.DB.prepare('SELECT id FROM wm_comments WHERE id = ? AND post_id = ? AND status = "approved"').bind(input.parentId, input.postId)
    );
    if (!parent) throw new Error('回复目标不存在');
  }
  const id = ulid();
  await env.DB.prepare(
    `INSERT INTO wm_comments(
      id, post_id, parent_id, user_id, guest_name, guest_email, guest_url, content, status, ip, user_agent, created_at
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
  )
    .bind(
      id,
      input.postId,
      input.parentId || null,
      input.user?.id || null,
      input.user ? null : input.guestName || '访客',
      input.user ? null : input.guestEmail || null,
      input.user ? null : input.guestUrl || null,
      input.content,
      input.status,
      input.ip || null,
      input.userAgent || null,
      nowSeconds()
    )
    .run();
  return id;
}

export async function deleteComment(env: Env['Bindings'], id: string, actor: CurrentUser): Promise<string[]> {
  const row = await first<{ user_id: string | null; post_author_id: string }>(
    env.DB.prepare(
      `SELECT c.user_id, p.author_id AS post_author_id
       FROM wm_comments c JOIN wm_posts p ON p.id = c.post_id
       WHERE c.id = ?`
    ).bind(id)
  );
  if (!row) throw new Error('评论不存在');
  if (actor.role !== 'admin' && actor.id !== row.user_id && actor.id !== row.post_author_id) throw new Error('无权删除评论');

  const ids = await all<{ id: string }>(
    env.DB.prepare(
      `WITH RECURSIVE tree(id) AS (
        SELECT id FROM wm_comments WHERE id = ?
        UNION ALL
        SELECT c.id FROM wm_comments c JOIN tree t ON c.parent_id = t.id
       )
       SELECT id FROM tree`
    ).bind(id)
  );
  await env.DB.prepare('DELETE FROM wm_comments WHERE id = ?').bind(id).run();
  return ids.map((item) => item.id);
}
