// src/server/entities/users.ts
import { text as text2, timestamp, check, boolean as boolean2, bigint, index as index2 } from "drizzle-orm/pg-core";
import { id as id2, timestamps as timestamps2 } from "@spfn/core/db";
import { sql } from "drizzle-orm";

// src/server/entities/roles.ts
import { text, boolean, integer, index } from "drizzle-orm/pg-core";
import { id, timestamps } from "@spfn/core/db";

// src/server/entities/schema.ts
import { createFunctionSchema } from "@spfn/core/db";
var authSchema = createFunctionSchema("@spfn/auth");

// src/server/entities/roles.ts
var roles = authSchema.table(
  "roles",
  {
    // Primary key
    id: id(),
    // Role identifier (used in code, e.g., 'admin', 'editor')
    // Must be unique, lowercase, kebab-case recommended
    name: text("name").notNull().unique(),
    // Display name for UI (e.g., 'Administrator', 'Content Editor')
    displayName: text("display_name").notNull(),
    // Role description
    description: text("description"),
    // Built-in role flag
    // true: Core package roles (user, admin, superadmin) - cannot be deleted
    // false: Custom or preset roles - can be deleted
    isBuiltin: boolean("is_builtin").notNull().default(false),
    // System role flag
    // true: Defined in code (builtin or preset) - deletion restricted
    // false: Runtime created custom role - fully manageable
    isSystem: boolean("is_system").notNull().default(false),
    // Active status
    // false: Deactivated role (users cannot be assigned)
    isActive: boolean("is_active").notNull().default(true),
    // Priority level (higher = more privileged)
    // superadmin: 100, admin: 80, user: 10
    // Used for role hierarchy and conflict resolution
    priority: integer("priority").notNull().default(10),
    ...timestamps()
  },
  (table) => [
    index("roles_name_idx").on(table.name),
    index("roles_is_system_idx").on(table.isSystem),
    index("roles_is_active_idx").on(table.isActive),
    index("roles_is_builtin_idx").on(table.isBuiltin),
    index("roles_priority_idx").on(table.priority)
  ]
);

// src/server/entities/users.ts
var users = authSchema.table(
  "users",
  {
    // Identity
    id: id2(),
    // Email address (unique identifier)
    // Used for: login, password reset, notifications
    email: text2("email").unique(),
    // Phone number in E.164 international format
    // Format: +[country code][number] (e.g., +821012345678)
    // Used for: SMS login, 2FA, notifications
    phone: text2("phone").unique(),
    // Authentication
    // Bcrypt password hash ($2b$10$[salt][hash], 60 chars)
    // Nullable to support OAuth-only accounts
    passwordHash: text2("password_hash"),
    // Force password change on next login
    // Use cases: initial setup, security breach, policy violation
    passwordChangeRequired: boolean2("password_change_required").notNull().default(false),
    // Authorization (Role-Based Access Control)
    // Foreign key to roles table
    // References built-in roles: user (default), admin, superadmin
    // Can also reference custom roles created at runtime
    roleId: bigint("role_id", { mode: "number" }).references(() => roles.id).notNull(),
    // Account status
    // - active: Normal operation (default)
    // - inactive: Deactivated (user request, dormant)
    // - suspended: Locked (security incident, ToS violation)
    status: text2(
      "status",
      {
        enum: ["active", "inactive", "suspended"]
      }
    ).notNull().default("active"),
    // Verification timestamps
    // null = unverified, timestamp = verified at this time
    // Email verification (via verification code or magic link)
    emailVerifiedAt: timestamp("email_verified_at", { withTimezone: true }),
    // Phone verification (via SMS OTP)
    phoneVerifiedAt: timestamp("phone_verified_at", { withTimezone: true }),
    // Metadata
    // Last successful login timestamp
    // Used for: security auditing, dormant account detection
    lastLoginAt: timestamp("last_login_at", { withTimezone: true }),
    ...timestamps2()
  },
  (table) => [
    // Database constraints
    // Ensure at least one identifier exists (email OR phone)
    check(
      "email_or_phone_check",
      sql`${table.email} IS NOT NULL OR ${table.phone} IS NOT NULL`
    ),
    // Indexes for query optimization
    index2("users_email_idx").on(table.email),
    index2("users_phone_idx").on(table.phone),
    index2("users_status_idx").on(table.status),
    index2("users_role_id_idx").on(table.roleId)
  ]
);
export {
  users
};
//# sourceMappingURL=users.js.map