import { Router } from "express";
import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { z } from "zod";

import { prisma } from "../db";

export const authRouter = Router();

const registerSchema = z.object({
  username: z.string().min(3),
  password: z.string().min(6),
  inviteCode: z.string().min(4),
});

authRouter.post("/register", async (req, res) => {
  const parsed = registerSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Invalid payload" });
  }

  const { username, password, inviteCode } = parsed.data;
  const now = new Date();

  try {
    const result = await prisma.$transaction(async (tx) => {
      const invite = await tx.invite.findFirst({
        where: {
          code: inviteCode,
          revokedAt: null,
          expiresAt: { gt: now },
        },
      });
      if (!invite || invite.usedCount >= invite.maxUses) {
        throw new Error("Invalid invite");
      }

      const existing = await tx.user.findUnique({ where: { username } });
      if (existing) {
        throw new Error("Username taken");
      }

      const passwordHash = await bcrypt.hash(password, 10);
      const user = await tx.user.create({
        data: { username, passwordHash },
      });

      await tx.invite.update({
        where: { id: invite.id },
        data: { usedCount: invite.usedCount + 1 },
      });

      return user;
    });

    const token = jwt.sign({ userId: result.id }, process.env.JWT_SECRET || "dev-secret", {
      expiresIn: "7d",
    });
    return res.json({ token, user: { id: result.id, username: result.username } });
  } catch (err) {
    const message = err instanceof Error ? err.message : "Register failed";
    const status = message === "Invalid invite" ? 400 : 409;
    return res.status(status).json({ error: message });
  }
});

const loginSchema = z.object({
  username: z.string().min(3),
  password: z.string().min(6),
});

authRouter.post("/login", async (req, res) => {
  const parsed = loginSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Invalid payload" });
  }

  const { username, password } = parsed.data;
  const user = await prisma.user.findUnique({ where: { username } });
  if (!user) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const ok = await bcrypt.compare(password, user.passwordHash);
  if (!ok) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET || "dev-secret", {
    expiresIn: "7d",
  });
  return res.json({ token, user: { id: user.id, username: user.username } });
});
