import { NextRequest, NextResponse } from "next/server";
import bcrypt from "bcryptjs";
import { prisma } from "@/lib/db";
import { sendVerificationEmail } from "@/lib/email-sender";

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    const { displayName, email, password, inviteToken } = body;

    if (!email || !password || !displayName) {
      return NextResponse.json(
        { error: "Name, email, and password are required" },
        { status: 400 }
      );
    }

    if (password.length < 8) {
      return NextResponse.json(
        { error: "Password must be at least 8 characters" },
        { status: 400 }
      );
    }

    const existing = await prisma.user.findUnique({ where: { email } });
    if (existing) {
      return NextResponse.json(
        { error: "An account with this email already exists" },
        { status: 409 }
      );
    }

    let inviteRole = "viewer";
    let inviteOrgId: string | null = null;

    if (inviteToken) {
      const invitation = await prisma.invitation.findUnique({
        where: { token: inviteToken },
      });

      if (!invitation) {
        return NextResponse.json({ error: "Invalid invitation" }, { status: 400 });
      }
      if (invitation.acceptedAt) {
        return NextResponse.json(
          { error: "This invitation has already been used" },
          { status: 400 }
        );
      }
      if (invitation.expiresAt < new Date()) {
        return NextResponse.json(
          { error: "This invitation has expired" },
          { status: 400 }
        );
      }
      if (invitation.email.toLowerCase() !== email.toLowerCase()) {
        return NextResponse.json(
          { error: "Email does not match invitation" },
          { status: 400 }
        );
      }

      inviteRole = invitation.role;
      inviteOrgId = invitation.organizationId;
    }

    const hashedPassword = await bcrypt.hash(password, 12);

    // Invite-based signups have already proven email ownership by clicking the
    // tokenized link we sent to that exact address, so we mark the email as
    // verified up-front and skip the post-registration verification email.
    const isInviteSignup = !!inviteOrgId;

    const user = await prisma.user.create({
      data: {
        email,
        displayName,
        hashedPassword,
        role: "viewer",
        emailVerified: isInviteSignup ? new Date() : null,
      },
    });

    if (inviteOrgId) {
      await prisma.orgMember.create({
        data: {
          userId: user.id,
          organizationId: inviteOrgId,
          role: inviteRole,
        },
      });

      await prisma.user.update({
        where: { id: user.id },
        data: { activeOrgId: inviteOrgId },
      });

      await prisma.invitation.update({
        where: { token: inviteToken },
        data: { acceptedAt: new Date() },
      });
    }

    // Domain auto-join: add user to any org whose allowedDomains match
    const emailDomain = email.split("@")[1]?.toLowerCase();
    if (emailDomain) {
      const matchingOrgs = await prisma.organization.findMany({
        where: { allowedDomains: { has: emailDomain } },
        select: { id: true },
      });

      for (const org of matchingOrgs) {
        if (org.id === inviteOrgId) continue;
        await prisma.orgMember.create({
          data: { userId: user.id, organizationId: org.id, role: "viewer" },
        });
      }

      if (!user.activeOrgId && matchingOrgs.length > 0) {
        const firstOrg = inviteOrgId ?? matchingOrgs[0].id;
        await prisma.user.update({
          where: { id: user.id },
          data: { activeOrgId: firstOrg },
        });
      }
    }

    if (!isInviteSignup) {
      try {
        const baseUrl = new URL(req.url).origin;
        await sendVerificationEmail(email, baseUrl);
      } catch (emailErr) {
        console.warn("[register] Verification email failed (non-blocking):", emailErr);
      }
    }

    return NextResponse.json({
      success: true,
      userId: user.id,
      emailVerified: isInviteSignup,
    });
  } catch (error) {
    console.error("[register] Error:", error);
    return NextResponse.json(
      { error: "Registration failed" },
      { status: 500 }
    );
  }
}
