import { randomUUID } from "node:crypto";
import bcrypt from "bcryptjs";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import { prisma } from "./prisma";
import { writeAuditLog } from "./permissions";

const SESSION_DAYS = 14;

export async function getCurrentUser() {
  const cookieStore = await cookies();
  const token = cookieStore.get(process.env.SESSION_COOKIE_NAME ?? "property_tracker_session")?.value;
  if (!token) return null;

  const session = await prisma.userSession.findUnique({
    where: { token },
    include: { user: true }
  });

  if (!session || session.expiresAt < new Date() || session.user.status === "DISABLED") {
    if (session) await prisma.userSession.delete({ where: { id: session.id } });
    return null;
  }

  return session.user;
}

export async function requireUser() {
  const user = await getCurrentUser();
  if (!user) redirect("/login");
  return user;
}

export function assertAdmin(role: string) {
  if (role !== "ADMIN" && role !== "OWNER") {
    throw new Error("This action requires an administrator or owner.");
  }
}

export async function createSession(login: string, password: string) {
  const normalizedLogin = login.trim();
  const user = await prisma.user.findFirst({
    where: {
      OR: [
        { username: normalizedLogin },
        { email: normalizedLogin.toLowerCase() }
      ]
    }
  });
  if (!user) return false;
  if (user.status === "DISABLED") return false;

  const valid = await bcrypt.compare(password, user.passwordHash);
  if (!valid) return false;

  const token = randomUUID();
  const expiresAt = new Date(Date.now() + SESSION_DAYS * 24 * 60 * 60 * 1000);
  await prisma.userSession.create({
    data: { userId: user.id, token, expiresAt }
  });
  await prisma.user.update({
    where: { id: user.id },
    data: { lastLoginAt: new Date() }
  });
  await writeAuditLog({
    userId: user.id,
    action: "login",
    entityType: "User",
    entityId: user.id
  });

  const cookieStore = await cookies();
  cookieStore.set(process.env.SESSION_COOKIE_NAME ?? "property_tracker_session", token, {
    httpOnly: true,
    sameSite: "lax",
    secure: process.env.NODE_ENV === "production",
    path: "/",
    expires: expiresAt
  });

  return true;
}

export async function destroySession() {
  const cookieStore = await cookies();
  const name = process.env.SESSION_COOKIE_NAME ?? "property_tracker_session";
  const token = cookieStore.get(name)?.value;
  if (token) {
    await prisma.userSession.deleteMany({ where: { token } });
  }
  cookieStore.delete(name);
}
