/**
 * Accept Organization Invitation API
 * GET - Validate invitation token and return details
 * POST - Accept invitation and create/add user to organization
 */

import bcrypt from "bcryptjs";
import { NextRequest, NextResponse } from "next/server";
import { logger } from "@/lib/logger";
import { convexMutation, convexQuery } from "@/lib/convex-client";
import { getRawConvexUserByEmail } from "@/lib/convex-auth-state";
import { acceptInvitationSchema } from "@/lib/validators/api-schemas";

export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const token = searchParams.get("token");

    if (!token) {
      return NextResponse.json(
        { success: false, error: "Token is required" },
        { status: 400 },
      );
    }

    const invitation = await convexQuery<Record<string, unknown>>(
      "organizations/queries:getInvitationByToken",
      { token },
    );

    if (!invitation) {
      return NextResponse.json(
        { success: false, error: "Invalid invitation token" },
        { status: 404 },
      );
    }

    if (Date.now() > Number(invitation.expiresAt)) {
      return NextResponse.json(
        { success: false, error: "Invitation has expired", expired: true },
        { status: 410 },
      );
    }

    if (invitation.status !== "PENDING") {
      return NextResponse.json(
        {
          success: false,
          error: `Invitation is ${String(invitation.status).toLowerCase()}`,
          status: invitation.status,
        },
        { status: 409 },
      );
    }

    const existingUser = await getRawConvexUserByEmail(
      String(invitation.email),
    );

    return NextResponse.json({
      success: true,
      invitation: {
        email: invitation.email,
        name: invitation.name ?? null,
        role: invitation.role,
        organizationName: invitation.organizationName ?? null,
        expiresAt: new Date(Number(invitation.expiresAt)).toISOString(),
      },
      userExists: Boolean(existingUser),
    });
  } catch (error: unknown) {
    logger.error(
      "[Accept Invitation API] Failed to validate invitation",
      error instanceof Error ? error : new Error(String(error)),
    );

    return NextResponse.json(
      { success: false, error: "Failed to validate invitation" },
      { status: 500 },
    );
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const parsed = acceptInvitationSchema.safeParse(body);

    if (!parsed.success) {
      return NextResponse.json(
        { success: false, error: parsed.error.errors.map(e => e.message).join(", ") },
        { status: 400 },
      );
    }

    const token = parsed.data.token;
    const password = parsed.data.password ?? "";
    const providedName = parsed.data.name ?? "";

    const invitation = await convexQuery<Record<string, unknown>>(
      "organizations/queries:getInvitationByToken",
      { token },
    );

    if (!invitation) {
      return NextResponse.json(
        { success: false, error: "Invalid invitation token" },
        { status: 404 },
      );
    }

    if (Date.now() > Number(invitation.expiresAt)) {
      return NextResponse.json(
        { success: false, error: "Invitation has expired" },
        { status: 410 },
      );
    }

    if (invitation.status !== "PENDING") {
      return NextResponse.json(
        {
          success: false,
          error: `Invitation is ${String(invitation.status).toLowerCase()}`,
        },
        { status: 409 },
      );
    }

    const email = String(invitation.email).toLowerCase();
    const existingUser = await getRawConvexUserByEmail(email);

    if (!existingUser && password.length < 8) {
      return NextResponse.json(
        {
          success: false,
          error: "Password is required (minimum 8 characters)",
        },
        { status: 400 },
      );
    }

    const userId =
      existingUser?.appUserId ??
      existingUser?.prismaId ??
      existingUser?._id ??
      (await convexMutation<string>("auth/mutations:createUserNoAuth", {
        email,
        name: providedName || String(invitation.name || email.split("@")[0]),
        password: await bcrypt.hash(password, 12),
      }));

    if (!userId) {
      throw new Error("Failed to resolve invited user");
    }

    if (existingUser && providedName && providedName !== existingUser.name) {
      await convexMutation("auth/mutations:updateUserNoAuth", {
        userId,
        name: providedName,
      });
    }

    const member = await convexMutation<{
      organizationId: string;
      role: string;
    }>("organizations/mutations:acceptInvitation", {
      token,
      userId,
      userName:
        providedName || existingUser?.name || String(invitation.name || ""),
    });

    logger.info("[Accept Invitation API] Invitation accepted", {
      userId,
      email,
      organizationId: member?.organizationId,
      role: member?.role,
    });

    return NextResponse.json({
      success: true,
      user: {
        id: userId,
        email,
        name: providedName || existingUser?.name || invitation.name || null,
      },
      member: {
        organizationId: member?.organizationId ?? invitation.organizationId,
        role: member?.role ?? invitation.role,
      },
    });
  } catch (error: unknown) {
    logger.error(
      "[Accept Invitation API] Failed to accept invitation",
      error instanceof Error ? error : new Error(String(error)),
    );

    const message =
      error instanceof Error ? error.message : "Failed to accept invitation";
    const status = message.includes("expired")
      ? 410
      : message.includes("Invalid")
        ? 404
        : message.includes("already")
          ? 409
          : 500;

    return NextResponse.json({ success: false, error: message }, { status });
  }
}
