import { randomBytes } from "node:crypto";

import { and, eq } from "drizzle-orm";

import {
  DEFAULT_INVITATION_MAX_USES,
  DEFAULT_INVITATION_VALIDITY_DAYS,
  MAX_INVITATION_MAX_USES,
  MAX_INVITATION_VALIDITY_DAYS,
  MIN_INVITATION_MAX_USES,
  MIN_INVITATION_VALIDITY_DAYS,
} from "@/modules/core/invitation-limits";
import { jsonFailure, jsonSuccess, readJsonBody } from "@/modules/core/server/api";
import { recordAuditLog } from "@/modules/core/server/audit";
import { requirePermission } from "@/modules/core/server/auth";
import { getDatabase } from "@/modules/core/server/db";
import { organizationInvitations, organizations, roles } from "@/modules/core/server/schema";

type RouteContext = {
  params: Promise<{
    id: string;
  }>;
};

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function readString(source: Record<string, unknown>, key: string): string {
  const value = source[key];
  return typeof value === "string" ? value.trim() : "";
}

function readBoundedInteger(
  source: Record<string, unknown>,
  key: string,
  options: {
    defaultValue: number;
    min: number;
    max: number;
    label: string;
  },
): { success: true; value: number } | { success: false; reason: string } {
  const rawValue = source[key];
  const value = rawValue === undefined || rawValue === null ? options.defaultValue : Number(rawValue);
  if (!Number.isInteger(value) || value < options.min || value > options.max) {
    return { success: false, reason: `${options.label}需为 ${options.min}-${options.max} 的整数` };
  }

  return { success: true, value };
}

function createInvitationToken(): string {
  return randomBytes(24).toString("base64url");
}

export async function POST(request: Request, context: RouteContext): Promise<Response> {
  const { id } = await context.params;
  const auth = await requirePermission("account:manage", {
    action: "organizationInvitation.create",
    targetType: "organization",
    targetId: id,
  });

  if (!auth.success) {
    return auth.response;
  }

  const activeOrganizationId = auth.context.organization?.id;
  if (activeOrganizationId && activeOrganizationId !== id) {
    return jsonFailure("不能为其他机构创建邀请", 403);
  }

  const body = await readJsonBody(request);
  if (!isRecord(body)) {
    return jsonFailure("请求数据格式无效");
  }

  const email = readString(body, "email");
  const roleId = readString(body, "roleId");
  if (!roleId) {
    return jsonFailure("请选择邀请角色");
  }

  const validityDaysResult = readBoundedInteger(body, "validityDays", {
    defaultValue: DEFAULT_INVITATION_VALIDITY_DAYS,
    min: MIN_INVITATION_VALIDITY_DAYS,
    max: MAX_INVITATION_VALIDITY_DAYS,
    label: "邀请有效期",
  });
  if (!validityDaysResult.success) {
    return jsonFailure(validityDaysResult.reason);
  }

  const maxUsesResult = readBoundedInteger(body, "maxUses", {
    defaultValue: DEFAULT_INVITATION_MAX_USES,
    min: MIN_INVITATION_MAX_USES,
    max: MAX_INVITATION_MAX_USES,
    label: "最大使用次数",
  });
  if (!maxUsesResult.success) {
    return jsonFailure(maxUsesResult.reason);
  }

  const database = getDatabase();
  const organizationRows = await database.select().from(organizations).where(eq(organizations.id, id)).limit(1);
  const organization = organizationRows[0];
  if (!organization) {
    return jsonFailure("机构不存在", 404);
  }

  const roleRows = await database
    .select()
    .from(roles)
    .where(and(eq(roles.id, roleId), eq(roles.organizationId, id), eq(roles.isEnabled, true)))
    .limit(1);
  const role = roleRows[0];
  if (!role) {
    return jsonFailure("角色不存在", 404);
  }

  const rows = await database
    .insert(organizationInvitations)
    .values({
      organizationId: id,
      roleId: role.id,
      email,
      token: createInvitationToken(),
      status: "active",
      createdByAccountId: auth.context.account.id,
      expiresAt: new Date(Date.now() + validityDaysResult.value * 24 * 60 * 60 * 1000),
      maxUses: maxUsesResult.value,
      usedCount: 0,
    })
    .returning();
  const invitation = rows[0];
  if (!invitation) {
    return jsonFailure("邀请创建失败", 500);
  }

  await recordAuditLog({
    actor: auth.context.account,
    organizationId: id,
    action: "organizationInvitation.create",
    targetType: "organizationInvitation",
    targetId: invitation.id,
    result: "success",
    reason: `创建机构邀请：${email || "通用邀请"}，有效期 ${validityDaysResult.value} 天，最多使用 ${maxUsesResult.value} 次`,
  });

  return jsonSuccess("邀请已创建", { invitation }, 201);
}
