import { eq } from "drizzle-orm";

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 { getRoleDefinitions, hasPermission } from "@/modules/core/server/permissions";
import { rolePermissions, roles } from "@/modules/core/server/schema";
import { PERMISSIONS } from "@/modules/core/types";
import type { Permission } from "@/modules/core/types";

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

const PERMISSION_SET = new Set<string>(PERMISSIONS);

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 readBoolean(source: Record<string, unknown>, key: string): boolean | null {
  const value = source[key];
  return typeof value === "boolean" ? value : null;
}

function readPermissionArray(source: Record<string, unknown>): Permission[] | null {
  const value = source.permissions;
  if (!Array.isArray(value)) {
    return null;
  }

  const permissions = value.filter((item): item is string => typeof item === "string");
  if (permissions.length !== value.length || permissions.some((permission) => !PERMISSION_SET.has(permission))) {
    return null;
  }

  return permissions as Permission[];
}

function createRoleKey(label: string): string {
  return label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
}

async function getEditableRole(id: string, organizationId: string | undefined, canManagePlatform: boolean) {
  const database = getDatabase();
  const rows = await database.select().from(roles).where(eq(roles.id, id)).limit(1);
  const role = rows[0];
  if (!role) {
    return { success: false as const, response: jsonFailure("角色不存在", 404) };
  }

  if (role.isSystem) {
    return { success: false as const, response: jsonFailure("内置角色不可编辑", 400) };
  }

  if (!canManagePlatform && role.organizationId !== organizationId) {
    return { success: false as const, response: jsonFailure("角色不存在", 404) };
  }

  return { success: true as const, role };
}

export async function PATCH(request: Request, context: RouteContext): Promise<Response> {
  const { id } = await context.params;
  const auth = await requirePermission("role:manage", {
    action: "role.update",
    targetType: "role",
    targetId: id,
  });

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

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

  const organizationId = auth.context.organization?.id;
  const editable = await getEditableRole(id, organizationId, hasPermission(auth.context.permissions, "platform:manage"));
  if (!editable.success) {
    return editable.response;
  }

  const label = readString(body, "label");
  const key = readString(body, "key") || (label ? createRoleKey(label) : "");
  const description = readString(body, "description");
  const isEnabled = "isEnabled" in body ? readBoolean(body, "isEnabled") : null;
  if ("isEnabled" in body && isEnabled === null) {
    return jsonFailure("角色状态无效");
  }

  const permissions = "permissions" in body ? readPermissionArray(body) : null;
  if ("permissions" in body && permissions === null) {
    return jsonFailure("权限列表无效");
  }

  if (!label && !key && !description && isEnabled === null && permissions === null) {
    return jsonFailure("请至少填写一个要更新的字段");
  }

  const updateValues: {
    label?: string;
    key?: string;
    description?: string;
    isEnabled?: boolean;
    updatedAt: Date;
  } = {
    updatedAt: new Date(),
  };

  if (label) {
    updateValues.label = label;
  }
  if (key) {
    updateValues.key = key;
  }
  if (description) {
    updateValues.description = description;
  }
  if (isEnabled !== null) {
    updateValues.isEnabled = isEnabled;
  }

  const database = getDatabase();
  try {
    await database.transaction(async (transaction) => {
      await transaction.update(roles).set(updateValues).where(eq(roles.id, id));
      if (permissions) {
        await transaction.delete(rolePermissions).where(eq(rolePermissions.roleId, id));
        if (permissions.length > 0) {
          await transaction.insert(rolePermissions).values(
            permissions.map((permissionId) => ({
              roleId: id,
              permissionId,
            })),
          );
        }
      }
    });
  } catch (error) {
    const message = error instanceof Error ? error.message : "";
    if (message.includes("roles_key_organization_unique")) {
      return jsonFailure("角色标识已存在", 409);
    }

    return jsonFailure("角色更新失败", 500);
  }

  await recordAuditLog({
    actor: auth.context.account,
    organizationId: editable.role.organizationId ?? organizationId,
    action: "role.update",
    targetType: "role",
    targetId: id,
    result: "success",
    reason: `更新角色：${label || editable.role.label}`,
  });

  const roleRows = await getRoleDefinitions(editable.role.organizationId ?? organizationId);
  const role = roleRows.find((item) => item.id === id);
  if (!role) {
    return jsonFailure("角色更新后读取失败", 500);
  }

  return jsonSuccess("角色已更新", { role });
}

export async function DELETE(_request: Request, context: RouteContext): Promise<Response> {
  const { id } = await context.params;
  const auth = await requirePermission("role:manage", {
    action: "role.disable",
    targetType: "role",
    targetId: id,
  });

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

  const organizationId = auth.context.organization?.id;
  const editable = await getEditableRole(id, organizationId, hasPermission(auth.context.permissions, "platform:manage"));
  if (!editable.success) {
    return editable.response;
  }

  const database = getDatabase();
  const rows = await database
    .update(roles)
    .set({ isEnabled: false, updatedAt: new Date() })
    .where(eq(roles.id, id))
    .returning();
  const role = rows[0];
  if (!role) {
    return jsonFailure("角色不存在", 404);
  }

  await recordAuditLog({
    actor: auth.context.account,
    organizationId: role.organizationId ?? organizationId,
    action: "role.disable",
    targetType: "role",
    targetId: role.id,
    result: "success",
    reason: `停用角色：${role.label}`,
  });

  return jsonSuccess("角色已停用", { role });
}
