import { SignJWT, jwtVerify } from "jose";
import { NextRequest, NextResponse } from "next/server";
import { ApiError } from "@/lib/api";

const COOKIE_NAME = "nw_token";
const TOKEN_MAX_AGE = 7 * 24 * 60 * 60; // 7 days in seconds

function getSecret() {
  const secret = process.env.JWT_SECRET;
  if (!secret) {
    throw new Error("JWT_SECRET environment variable is not set");
  }
  return new TextEncoder().encode(secret);
}

export async function signToken(userId: string): Promise<string> {
  return new SignJWT({ sub: userId })
    .setProtectedHeader({ alg: "HS256" })
    .setIssuedAt()
    .setExpirationTime(`${TOKEN_MAX_AGE}s`)
    .sign(getSecret());
}

export async function verifyToken(token: string): Promise<string> {
  const { payload } = await jwtVerify(token, getSecret());
  if (!payload.sub) throw new Error("Invalid token payload");
  return payload.sub;
}

export function setAuthCookie(res: NextResponse, token: string): NextResponse {
  res.cookies.set(COOKIE_NAME, token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    path: "/",
    maxAge: TOKEN_MAX_AGE,
  });
  return res;
}

export function clearAuthCookie(res: NextResponse): NextResponse {
  res.cookies.set(COOKIE_NAME, "", {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    path: "/",
    maxAge: 0,
  });
  return res;
}

/**
 * Extracts authenticated userId from JWT cookie.
 * Throws 401 if no valid token is present.
 */
export async function getAuthUserId(req: NextRequest): Promise<string> {
  const token = req.cookies.get(COOKIE_NAME)?.value;
  if (!token) {
    throw new ApiError("请先登录", 401);
  }
  try {
    return await verifyToken(token);
  } catch {
    throw new ApiError("登录已过期，请重新登录", 401);
  }
}

/**
 * Optionally extracts userId from JWT cookie.
 * Returns null if no valid token (does not throw).
 */
export async function getOptionalAuthUserId(req: NextRequest): Promise<string | null> {
  const token = req.cookies.get(COOKIE_NAME)?.value;
  if (!token) return null;
  try {
    return await verifyToken(token);
  } catch {
    return null;
  }
}
