/**
 * Organization Invitations API
 * POST - Send a team member invitation
 * GET - Get pending invitations for current organization
 *
 * Authentication: Required
 * Authorization: Organization OWNER or ADMIN only
 */

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { getAuthenticatedEmail } from "@/lib/utils/auth-helpers.util";
import { CONVEX_PATHS } from "@/lib/convex-paths";
import { sendTeamInvitation } from "@/lib/services/team-invitation-emails.service";
import { logger } from "@/lib/logger";
import { prisma } from "@/lib/db";
import { convexMutation, convexQuery } from "@/lib/convex-client";
import crypto from "crypto";
import { organizationInvitationSchema } from "@/lib/validators/api-schemas";

/**
 * POST /api/organization/invitations
 * Send a team member invitation
 */
export async function POST(request: NextRequest) {
  try {
    const userEmail = await getAuthenticatedEmail(request, auth);

    if (!userEmail) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    // Parse and validate request body
    const body = await request.json();
    const parsed = organizationInvitationSchema.safeParse(body);

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

    const { email, name, role } = parsed.data;

    // Get user with organization membership
    const user = await prisma.users.findUnique({
      where: { email: userEmail },
      select: { id: true, name: true, email: true },
    });

    if (!user) {
      return NextResponse.json(
        { success: false, error: "User not found" },
        { status: 404 },
      );
    }

    const orgState = await convexQuery<{
      organization: { id: string; name: string };
      members: Array<{
        user: { email: string } | null;
      }>;
      pendingInvitations: Array<{ email: string }>;
      seatConfig: { availableSeats: number };
      userRole: string;
    }>("organizations/queries:getOrganizationStateByUserId", {
      userId: user.id,
    });

    if (!orgState || !["OWNER", "ADMIN"].includes(orgState.userRole)) {
      return NextResponse.json(
        {
          success: false,
          error: "Only organization owners and admins can send invitations",
        },
        { status: 403 },
      );
    }

    const isExistingMember = orgState.members.some(
      (member) => member.user?.email?.toLowerCase() === email,
    );
    if (isExistingMember) {
      return NextResponse.json(
        {
          success: false,
          error: "User is already a member of this organization",
        },
        { status: 409 },
      );
    }

    const hasPendingInvite = orgState.pendingInvitations.some(
      (invitation) => invitation.email.toLowerCase() === email,
    );
    if (hasPendingInvite) {
      return NextResponse.json(
        {
          success: false,
          error: "An invitation has already been sent to this email",
        },
        { status: 409 },
      );
    }

    if (orgState.seatConfig.availableSeats <= 0) {
      return NextResponse.json(
        {
          success: false,
          error:
            "No available seats. Please upgrade your plan or purchase additional seats.",
        },
        { status: 409 },
      );
    }

    const token = crypto.randomBytes(24).toString("hex");
    const expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1000;

    await convexMutation(CONVEX_PATHS.createOrganizationInvitation, {
      organizationId: orgState.organization.id,
      email,
      name,
      role,
      token,
      invitedBy: user.id,
      expiresAt,
    });

    const emailResult = await sendTeamInvitation({
      email,
      inviteeName: name,
      orgName: orgState.organization.name,
      inviterName: user.name || user.email,
      role,
      token,
      expiresAt: new Date(expiresAt),
      lang: "en",
    });

    if (!emailResult.success) {
      logger.warn("[Invitations API] Failed to send invitation email", {
        email,
        error: emailResult.error,
      });
    }

    logger.info("[Invitations API] Invitation created", {
      organizationId: orgState.organization.id,
      email,
      role,
      invitedBy: user.id,
      emailSent: emailResult.success,
    });

    return NextResponse.json(
      {
        success: true,
        invitation: {
          email,
          name: name ?? null,
          role,
          status: "PENDING",
          expiresAt: new Date(expiresAt).toISOString(),
        },
      },
      { status: 201 },
    );
  } catch (error: unknown) {
    logger.error("[Invitations API] Failed to send invitation", error);

    // Return user-friendly error messages
    const errorMessage =
      error instanceof Error ? error.message : "Failed to send invitation";
    const status = errorMessage.includes("already") ? 409 : 500;

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

/**
 * GET /api/organization/invitations
 * Get pending invitations for current organization
 */
export async function GET(request: NextRequest) {
  try {
    const userEmail = await getAuthenticatedEmail(request, auth);

    if (!userEmail) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    const user = await prisma.users.findUnique({
      where: { email: userEmail },
      select: { id: true },
    });

    if (!user) {
      return NextResponse.json(
        { success: false, error: "User not found" },
        { status: 404 },
      );
    }

    const orgState = await convexQuery<{
      pendingInvitations: Array<Record<string, unknown>>;
      userRole: string;
    }>("organizations/queries:getOrganizationStateByUserId", {
      userId: user.id,
    });

    if (!orgState || !["OWNER", "ADMIN"].includes(orgState.userRole)) {
      return NextResponse.json(
        {
          success: false,
          error: "Only organization owners and admins can view invitations",
        },
        { status: 403 },
      );
    }

    return NextResponse.json({
      success: true,
      invitations: orgState.pendingInvitations,
    });
  } catch (error: unknown) {
    logger.error("[Invitations API] Failed to get invitations", error);

    return NextResponse.json(
      {
        success: false,
        error:
          error instanceof Error ? error.message : "Failed to get invitations",
      },
      { status: 500 },
    );
  }
}
