import { randomBytes } from "crypto";
import bcrypt from "bcryptjs";
import { Cookie } from "rjweb-server";
import { prisma } from "../lib/db";
import { makeResponse } from "../lib/response";
import { ERROR_MESSAGES } from "../lib/errors";
import { createLogger } from "../lib/logger";

const log = createLogger("AUTH_ROUTE");
const COOKIE_NAME = "pp_session";
const COOKIE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;

export async function loginHandler(ctr: any) {
  let body: any;
  try {
    body = await ctr.body();
  } catch {
    return makeResponse({ ctr, content: { code: 400, message: "Invalid body" } });
  }

  const { username, password } = body || {};
  if (!username || !password) {
    return makeResponse({ ctr, content: { code: 400, message: "Username and password required" } });
  }

  const user = await prisma.user.findUnique({ where: { username } });
  if (!user) {
    return makeResponse({ ctr, content: { code: 401, message: "Invalid credentials" } });
  }

  const valid = await bcrypt.compare(password, user.passwordHash);
  if (!valid) {
    return makeResponse({ ctr, content: { code: 401, message: "Invalid credentials" } });
  }

  const sessionHash = randomBytes(32).toString("hex");
  await prisma.session.create({ data: { hash: sessionHash, userId: user.id } });

  ctr.cookies.set(
    COOKIE_NAME,
    new Cookie(sessionHash, {
      httpOnly: true,
      expires: new Date(Date.now() + COOKIE_MAX_AGE_MS),
      path: "/",
      sameSite: "lax",
    }),
  );

  return makeResponse({ ctr, content: { code: 200, data: { id: user.id, username: user.username, isAdmin: user.isAdmin } } });
}

export async function logoutHandler(ctr: any) {
  const auth = ctr.getAuth?.();
  if (auth?.success) {
    await prisma.session.delete({ where: { id: auth.sessionId } }).catch(() => {});
  }
  ctr.cookies.set(COOKIE_NAME, new Cookie("", { expires: new Date(0), path: "/" }));
  return makeResponse({ ctr, content: { code: 200, message: "Logged out" } });
}

export async function meHandler(ctr: any) {
  const auth = ctr.getAuth?.();
  if (!auth?.success) {
    return makeResponse({ ctr, content: { code: ERROR_MESSAGES.UNAUTHORIZED.code, message: ERROR_MESSAGES.UNAUTHORIZED.message } });
  }

  const user = await prisma.user.findUnique({ where: { id: auth.user.id } });
  if (!user) return makeResponse({ ctr, content: { code: 404, message: "User not found" } });

  return makeResponse({
    ctr,
    content: {
      code: 200,
      data: {
        id: user.id,
        username: user.username,
        isAdmin: user.isAdmin,
        isFounder: user.isFounder,
        giteaUsername: user.giteaUsername,
        giteaInstanceUrl: user.giteaInstanceUrl,
        giteaPatSet: !!user.giteaPAT,
        awsAccessKeyId: user.awsAccessKeyId ? "****" : null,
        awsRegion: user.awsRegion,
        awsConfigured: !!(user.awsAccessKeyId && user.awsSecretAccessKey && user.awsRegion),
        setupComplete: !!(user.giteaInstanceUrl && user.giteaPAT && user.awsAccessKeyId && user.awsSecretAccessKey && user.awsRegion),
      },
    },
  });
}

export async function setupStatusHandler(ctr: any) {
  const count = await prisma.user.count();
  return makeResponse({ ctr, content: { code: 200, data: { needsSetup: count === 0 } } });
}

export async function firstUserHandler(ctr: any) {
  const count = await prisma.user.count();
  if (count > 0) {
    return makeResponse({ ctr, content: { code: 403, message: "Setup already completed. Contact an administrator to create your account." } });
  }

  let body: any;
  try {
    body = await ctr.body();
  } catch {
    return makeResponse({ ctr, content: { code: 400, message: "Invalid body" } });
  }

  const { username, password } = body || {};
  if (!username || !password || password.length < 8) {
    return makeResponse({ ctr, content: { code: 400, message: "Username and password (min 8 chars) required" } });
  }

  const hash = await bcrypt.hash(password, 12);
  const user = await prisma.user.create({
    data: { username, passwordHash: hash, isAdmin: true, isFounder: true },
  });

  // Auto-create a webhook token so it's immediately available in the setup wizard
  const webhookSecret = randomBytes(32).toString("hex");
  await prisma.webhookToken.create({ data: { userId: user.id, token: webhookSecret } });

  const sessionHash = randomBytes(32).toString("hex");
  await prisma.session.create({ data: { hash: sessionHash, userId: user.id } });

  ctr.cookies.set(
    COOKIE_NAME,
    new Cookie(sessionHash, {
      httpOnly: true,
      expires: new Date(Date.now() + COOKIE_MAX_AGE_MS),
      path: "/",
      sameSite: "lax",
    }),
  );

  log.info({ username }, "First user (founder) created");
  return makeResponse({ ctr, content: { code: 201, data: { id: user.id, username: user.username, isAdmin: true, isFounder: true } } });
}
