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

import { getDatabase } from "@/modules/core/server/db";
import { permissions, rolePermissions, roles } from "@/modules/core/server/schema";
import { ensureSystemSettings } from "@/modules/core/server/system-settings";
import type { Permission, RoleDefinition, RoleId } from "@/modules/core/types";
import { PERMISSIONS, ROLE_LABELS } from "@/modules/core/types";

type PermissionDefinition = {
  id: Permission;
  label: string;
  category: string;
  description: string;
};

export const PERMISSION_DEFINITIONS: PermissionDefinition[] = [
  { id: "platform:manage", label: "平台管理", category: "平台", description: "管理平台级配置和跨机构操作。" },
  { id: "organization:read", label: "查看机构", category: "机构", description: "查看机构、院区和租户信息。" },
  { id: "organization:manage", label: "管理机构", category: "机构", description: "创建、编辑和停用机构。" },
  { id: "account:read", label: "查看用户", category: "用户", description: "查看账号、成员和申请。" },
  { id: "account:manage", label: "管理用户", category: "用户", description: "创建、审批、启停和分配用户。" },
  { id: "role:read", label: "查看角色", category: "权限", description: "查看角色和权限矩阵。" },
  { id: "role:manage", label: "管理角色", category: "权限", description: "创建自定义角色并配置权限组合。" },
  { id: "permission:read", label: "查看权限", category: "权限", description: "查看系统注册权限点。" },
  { id: "audit:read", label: "查看审计", category: "审计", description: "查看关键操作审计日志。" },
  { id: "incident:read", label: "查看故障", category: "运维", description: "查看系统健康和故障中心。" },
  { id: "incident:manage", label: "处理故障", category: "运维", description: "确认、处理和关闭故障事件。" },
  { id: "facility:read", label: "查看房间床位", category: "床位", description: "查看房间、床位和占用状态。" },
  { id: "facility:manage", label: "管理房间床位", category: "床位", description: "维护院区、房间、床位和床位状态。" },
  { id: "admission:read", label: "查看入住", category: "入住", description: "查看入住、换床、退住历史。" },
  { id: "admission:manage", label: "管理入住", category: "入住", description: "办理入住、换床和退住。" },
  { id: "elder:read", label: "查看老人档案", category: "老人", description: "查看老人基础档案。" },
  { id: "elder:create", label: "新增老人档案", category: "老人", description: "创建老人档案。" },
  { id: "elder:update", label: "更新老人档案", category: "老人", description: "更新老人档案和照护信息。" },
  { id: "elder:delete", label: "删除老人档案", category: "老人", description: "删除老人档案。" },
];

type SeedRole = {
  key: RoleId;
  scope: "platform" | "organization";
  description: string;
  permissions: Permission[];
};

export const SYSTEM_ROLE_DEFINITIONS: SeedRole[] = [
  {
    key: "platform_admin",
    scope: "platform",
    description: "平台最高权限，管理所有机构、角色、审计和故障中心。",
    permissions: [...PERMISSIONS],
  },
  {
    key: "platform_operator",
    scope: "platform",
    description: "平台运营角色，管理机构和跨机构用户配置。",
    permissions: [
      "organization:read",
      "organization:manage",
      "account:read",
      "account:manage",
      "role:read",
      "permission:read",
      "audit:read",
      "incident:read",
    ],
  },
  {
    key: "platform_auditor",
    scope: "platform",
    description: "平台审计角色，只读查看机构、审计和故障。",
    permissions: ["organization:read", "account:read", "role:read", "permission:read", "audit:read", "incident:read"],
  },
  {
    key: "platform_ops",
    scope: "platform",
    description: "平台运维角色，处理系统故障和运行状态。",
    permissions: ["organization:read", "audit:read", "incident:read", "incident:manage"],
  },
  {
    key: "org_admin",
    scope: "organization",
    description: "机构管理员，管理本机构用户、角色、房间床位、入住和审计。",
    permissions: [
      "organization:read",
      "account:read",
      "account:manage",
      "role:read",
      "role:manage",
      "permission:read",
      "audit:read",
      "incident:read",
      "facility:read",
      "facility:manage",
      "admission:read",
      "admission:manage",
      "elder:read",
      "elder:create",
      "elder:update",
      "elder:delete",
    ],
  },
  {
    key: "manager",
    scope: "organization",
    description: "运营主管，处理老人档案、床位入住和审计查看。",
    permissions: [
      "account:read",
      "role:read",
      "audit:read",
      "facility:read",
      "facility:manage",
      "admission:read",
      "admission:manage",
      "elder:read",
      "elder:create",
      "elder:update",
      "elder:delete",
    ],
  },
  {
    key: "caregiver",
    scope: "organization",
    description: "照护人员，查看床位和维护老人照护信息。",
    permissions: ["facility:read", "admission:read", "elder:read", "elder:update"],
  },
  {
    key: "viewer",
    scope: "organization",
    description: "只读访客，查看老人、床位和入住信息。",
    permissions: ["facility:read", "admission:read", "elder:read"],
  },
];

export async function ensureSystemDefaults(): Promise<void> {
  const database = getDatabase();
  await ensureSystemSettings();

  await database
    .insert(permissions)
    .values(PERMISSION_DEFINITIONS)
    .onConflictDoUpdate({
      target: permissions.id,
      set: {
        label: permissions.label,
        category: permissions.category,
        description: permissions.description,
        isEnabled: true,
      },
    });

  const existingRoles = await database.select().from(roles).where(isNull(roles.organizationId));
  const existingRoleKeys = new Set(existingRoles.map((role) => role.key));
  const seedRoles = SYSTEM_ROLE_DEFINITIONS.filter((role) => role.scope === "platform" && !existingRoleKeys.has(role.key));

  if (seedRoles.length > 0) {
    await database.insert(roles).values(
      seedRoles.map((role) => ({
        key: role.key,
        scope: role.scope,
        label: ROLE_LABELS[role.key],
        description: role.description,
        isSystem: true,
        isEnabled: true,
      })),
    );
  }

  const platformRoles = await database.select().from(roles).where(isNull(roles.organizationId));
  const inserts = platformRoles.flatMap((role) => {
    const definition = SYSTEM_ROLE_DEFINITIONS.find((item) => item.key === role.key);
    if (!definition) {
      return [];
    }

    return definition.permissions.map((permissionId) => ({
      roleId: role.id,
      permissionId,
    }));
  });

  if (inserts.length > 0) {
    await database.insert(rolePermissions).values(inserts).onConflictDoNothing();
  }
}

export async function seedOrganizationRoles(organizationId: string): Promise<void> {
  const database = getDatabase();
  const organizationRoles = SYSTEM_ROLE_DEFINITIONS.filter((role) => role.scope === "organization");

  await database
    .insert(roles)
    .values(
      organizationRoles.map((role) => ({
        key: role.key,
        organizationId,
        scope: role.scope,
        label: ROLE_LABELS[role.key],
        description: role.description,
        isSystem: true,
        isEnabled: true,
      })),
    )
    .onConflictDoNothing();

  const seededRoles = await database
    .select()
    .from(roles)
    .where(and(eq(roles.organizationId, organizationId), inArray(roles.key, organizationRoles.map((role) => role.key))));

  const inserts = seededRoles.flatMap((role) => {
    const definition = SYSTEM_ROLE_DEFINITIONS.find((item) => item.key === role.key);
    if (!definition) {
      return [];
    }

    return definition.permissions.map((permissionId) => ({ roleId: role.id, permissionId }));
  });

  if (inserts.length > 0) {
    await database.insert(rolePermissions).values(inserts).onConflictDoNothing();
  }
}

export async function getRoleDefinitions(organizationId?: string): Promise<RoleDefinition[]> {
  const database = getDatabase();
  const rows = await database
    .select()
    .from(roles)
    .where(organizationId ? or(isNull(roles.organizationId), eq(roles.organizationId, organizationId)) : isNull(roles.organizationId));

  const roleIds = rows.map((role) => role.id);
  const permissionRows =
    roleIds.length > 0
      ? await database.select().from(rolePermissions).where(inArray(rolePermissions.roleId, roleIds))
      : [];

  return rows.map((role) => ({
    id: role.id,
    key: role.key,
    label: role.label,
    description: role.description,
    scope: role.scope,
    organizationId: role.organizationId ?? undefined,
    isSystem: role.isSystem,
    isEnabled: role.isEnabled,
    permissions: permissionRows
      .filter((permission) => permission.roleId === role.id)
      .map((permission) => permission.permissionId as Permission),
  }));
}

export async function getPermissionsForRole(roleId: string): Promise<Permission[]> {
  const database = getDatabase();
  const rows = await database
    .select({ permissionId: rolePermissions.permissionId })
    .from(rolePermissions)
    .innerJoin(roles, eq(roles.id, rolePermissions.roleId))
    .where(and(eq(rolePermissions.roleId, roleId), eq(roles.isEnabled, true)));
  return rows.map((row) => row.permissionId as Permission);
}

export function hasPermission(permissionsList: readonly Permission[], permission: Permission): boolean {
  return permissionsList.includes(permission);
}
