import { z } from "zod";
import { NextRequest } from "next/server";
import { apiError, apiOk, requireApiToken } from "@/lib/api-auth";
import { prisma } from "@/lib/db";
import { deleteArticle, updateArticle } from "@/lib/articles-repo";

export const runtime = "nodejs";

async function findByIdOrSlug(idOrSlug: string) {
  return prisma.article.findFirst({
    where: { OR: [{ id: idOrSlug }, { slug: idOrSlug }] },
    include: {
      category: { select: { slug: true, name: true } },
      author: { select: { id: true, name: true, email: true } },
      tags: { include: { tag: { select: { slug: true, name: true } } } },
    },
  });
}

// GET /api/v1/articles/{idOrSlug}
export async function GET(
  req: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const ctx = await requireApiToken(req, ["post:read"]);
  if (ctx instanceof Response) return ctx;

  const { id } = await params;
  const a = await findByIdOrSlug(id);
  if (!a) return apiError(404, "not_found", "Không tìm thấy bài viết.");
  return apiOk(a);
}

// PATCH /api/v1/articles/{idOrSlug}
const UpdateBody = z.object({
  title: z.string().min(1).max(200).optional(),
  slug: z.string().max(96).optional(),
  excerpt: z.string().max(500).optional(),
  content: z.string().min(1).optional(),
  coverImage: z.string().url().nullable().optional(),
  status: z.enum(["draft", "published", "scheduled", "archived"]).optional(),
  publishedAt: z.coerce.date().nullable().optional(),
  scheduledFor: z.coerce.date().nullable().optional(),
  metaTitle: z.string().max(120).optional(),
  metaDesc: z.string().max(300).optional(),
  metaKeywords: z.string().max(300).optional(),
  focusKeyword: z.string().max(80).optional(),
  ogImage: z.string().url().optional(),
  canonicalUrl: z.string().url().optional(),
  noIndex: z.boolean().optional(),
  categoryId: z.string().optional(),
  categorySlug: z.string().optional(),
  tags: z.array(z.string()).max(20).optional(),
});

export async function PATCH(
  req: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const ctx = await requireApiToken(req, ["post:write"]);
  if (ctx instanceof Response) return ctx;

  const { id } = await params;
  const a = await findByIdOrSlug(id);
  if (!a) return apiError(404, "not_found", "Không tìm thấy bài viết.");

  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return apiError(400, "bad_json", "Body không phải JSON hợp lệ.");
  }
  const parsed = UpdateBody.safeParse(body);
  if (!parsed.success)
    return apiError(400, "bad_body", "Body không hợp lệ.", parsed.error.flatten());

  if (parsed.data.status === "published" && !ctx.scopes.includes("post:publish"))
    return apiError(
      403,
      "insufficient_scope",
      "Token cần scope post:publish để chuyển sang published.",
    );

  try {
    const updated = await updateArticle({ id: a.id, ...parsed.data, authorId: a.authorId });
    await ctx.audit({
      action: "article.update",
      target: updated.id,
      meta: { fields: Object.keys(parsed.data) },
    });
    return apiOk({
      id: updated.id,
      slug: updated.slug,
      status: updated.status,
      seoScore: updated.seoScore,
    });
  } catch (err) {
    return apiError(500, "update_failed", String(err instanceof Error ? err.message : err));
  }
}

// DELETE /api/v1/articles/{idOrSlug}
export async function DELETE(
  req: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const ctx = await requireApiToken(req, ["post:delete"]);
  if (ctx instanceof Response) return ctx;
  const { id } = await params;
  const a = await findByIdOrSlug(id);
  if (!a) return apiError(404, "not_found", "Không tìm thấy.");
  await deleteArticle(a.id);
  await ctx.audit({ action: "article.delete", target: a.id, meta: { slug: a.slug } });
  return apiOk({ id: a.id, deleted: true });
}
