import crypto from "node:crypto";
import type { Collection } from "mongodb";
import { getDb } from "@/lib/mongodb";

/**
 * Admin & CMS data layer — backed by MongoDB (Atlas in production).
 *
 * Server-only: imports the Mongo client (a secret-bearing module). Never import
 * from a client component.
 */

export type AdminLevel = "MAIN_ADMIN" | "SUB_ADMIN";

export type AdminRole =
  | "MAIN_ADMIN"
  | "CONTENT_EDITOR"
  | "PUBLISHING_MANAGER"
  | "SEO_MANAGER"
  | "MEDIA_MANAGER";

export type AdminStatus = "ACTIVE" | "SUSPENDED" | "DISABLED";

export interface AdminUser {
  id: string;
  email: string;
  name: string;
  level: AdminLevel;
  role: AdminRole | string;
  status: AdminStatus;
  passwordHash: string;
  passwordSalt: string;
  passwordChangeRequired: boolean;
  twoFactorEnabled: boolean;
  twoFactorSecret?: string | null;
  twoFactorBackupCodes?: string[];
  // ── PIN & Biometric Screen Lock ──
  pinHash?: string | null;
  pinSalt?: string | null;
  pinSetupRequired?: boolean;
  webauthnCredentials?: Array<{
    id: string;
    publicKey: string;
    counter: number;
    transports?: string[];
    createdAt: string;
  }>;
  // ── Author / public profile (identity separate from security & role) ──
  // These power the public author page, blog article author card and Article
  // schema. They are editable profile data — never security credentials.
  displayName?: string;
  jobTitle?: string;
  shortBio?: string;
  longBio?: string;
  avatarMediaId?: string | null;
  avatarUrl?: string | null;
  authorSlug?: string;
  displayOrder?: number;
  location?: string;
  professionalEmail?: string;
  socials?: AuthorSocials;
  createdAt: string;
  updatedAt: string;
  lastLoginAt: string | null;
  createdBy: string | null;
}

export interface AuthorSocials {
  linkedin?: string;
  instagram?: string;
  x?: string;
  website?: string;
  github?: string;
  youtube?: string;
}

/** Social platforms the profile editor exposes (Quto AI-relevant only). */
export const AUTHOR_SOCIAL_KEYS = [
  "linkedin",
  "instagram",
  "x",
  "website",
  "github",
  "youtube",
] as const;

export type SessionStatus = "ACTIVE" | "REVOKED" | "EXPIRED" | "BLOCKED";

export interface AdminSession {
  id: string;
  userId: string;
  tokenHash: string;
  status: SessionStatus;
  ipAddress: string | null;
  userAgent: string | null;
  device: string | null;
  browser: string | null;
  browserVersion?: string | null;
  operatingSystem?: string | null;
  deviceType?: "Desktop" | "Mobile" | "Tablet" | "Unknown";
  createdAt: string;
  lastActiveAt: string;
  lastSeenAt: string;
  expiresAt: string;
  revoked: boolean;
  revokedAt: string | null;
  revokedBy: string | null;
  revokeReason: string | null;
  revokedReason?: string | null;
  isLocked?: boolean;
  lockedAt?: string | null;
  location?: AuditLocation | null;
  networkSecurity?: NetworkSecurityInfo | null;
}

export type ResetRequestStatus = "PENDING" | "APPROVED" | "REJECTED" | "EXPIRED";

export interface PasswordResetRequest {
  id: string;
  userId: string;
  email: string;
  name: string;
  status: ResetRequestStatus;
  requestedAt: string;
  handledAt: string | null;
  handledBy: string | null;
  handlingReason: string | null;
  expiresAt: string;
}

export interface NetworkSecurityInfo {
  ip: string;
  isVpn: boolean;
  isProxy: boolean;
  isTor: boolean;
  isRelay: boolean;
  isBlocked: boolean;
  blockReason?: string | null;
  risk: "LOW" | "MEDIUM" | "HIGH";
  asn?: string;
  country?: string;
  city?: string;
  provider: string;
  checkedAt: string;
}

export interface AuditLocation {
  status: "available" | "denied" | "unavailable";
  latitude?: number;
  longitude?: number;
  address?: string;
  locality?: string;
  city?: string;
  region?: string;
  country?: string;
  postalCode?: string;
  source?: string;
  capturedAt?: string;
}

export type SecurityAction =
  | "ADMIN_BOOTSTRAP"
  | "ADMIN_CREATED"
  | "ADMIN_SUSPENDED"
  | "ADMIN_REACTIVATED"
  | "ROLE_CHANGED"
  | "FORCE_LOGOUT"
  | "FORCE_LOGOUT_ALL"
  | "PASSWORD_CHANGE"
  | "PASSWORD_RESET_REQUESTED"
  | "PASSWORD_RESET_COMPLETED"
  | "PASSWORD_RESET_REJECTED"
  | "LOGIN_SUCCESS"
  | "LOGIN_FAILURE"
  | "LOGOUT"
  | "SESSION_LOGOUT"
  | "SESSION_EXPIRED"
  | "SESSION_REVOKED"
  | "SESSION_LOCKED"
  | "SESSION_UNLOCKED"
  | "TWO_FACTOR_ENABLED"
  | "TWO_FACTOR_DISABLED"
  | "SETTINGS_CHANGED"
  | "PROFILE_UPDATED"
  | "PIN_CHANGED"
  | "PIN_SETUP"
  | "PIN_FAILED"
  | "PIN_LOCKOUT"
  | "WEBAUTHN_REGISTERED"
  | "WEBAUTHN_REMOVED"
  | "WEBAUTHN_AUTH_SUCCESS"
  | "WEBAUTHN_AUTH_FAILED"
  | "NETWORK_SECURITY_BLOCKED"
  | "NETWORK_SECURITY_VERIFIED";

export interface SecurityAuditLog {
  id: string;
  actorId: string;
  actorName: string;
  actorEmail: string;
  actorLevel: AdminLevel | "SYSTEM";
  targetUserId: string | null;
  targetUserEmail: string | null;
  targetUserName: string | null;
  action: SecurityAction;
  details: Record<string, unknown>;
  ipAddress: string | null;
  userAgent?: string | null;
  location?: AuditLocation | null;
  networkSecurity?: NetworkSecurityInfo | null;
  timestamp: string;
}

export type ContentAction =
  | "POST_CREATED"
  | "POST_EDITED"
  | "POST_BANNER_CHANGED"
  | "POST_SCHEDULED"
  | "POST_PUBLISHED"
  | "POST_UNPUBLISHED"
  | "POST_UPDATED_LIVE"
  | "POST_ARCHIVED"
  | "POST_DELETED"
  | "POST_RESTORED"
  | "POST_DUPLICATED"
  | "TITLE_CHANGED"
  | "SLUG_CHANGED"
  | "SEO_METADATA_UPDATED"
  | "REVISION_RESTORED"
  | "MEDIA_CHANGED"
  | "MEDIA_UPLOADED"
  | "MEDIA_REPLACED"
  | "MEDIA_DELETED"
  | "MEDIA_METADATA_UPDATED"
  | "MEDIA_ATTACHED"
  | "MEDIA_DETACHED"
  | "MEDIA_BULK_UPLOADED"
  | "MEDIA_BULK_DELETED"
  | "CATEGORY_CREATED"
  | "CATEGORY_UPDATED"
  | "CATEGORY_DELETED"
  | "REDIRECT_CREATED"
  | "REDIRECT_DELETED"
  | "PUSH_NOTIFICATION_SENT";

export interface ContentActivityLog {
  id: string;
  actorId: string;
  actorName: string;
  actorEmail: string;
  actorRole: AdminRole | string;
  postId: string | null;
  postTitle: string | null;
  postSlug: string | null;
  action: ContentAction;
  details: Record<string, unknown>;
  location?: AuditLocation | null;
  timestamp: string;
}

export interface AdminSettings {
  require2FAForAllSubAdmins: boolean;
  sessionTimeoutMinutes: number;
  maxLoginAttempts: number;
  updatedAt: string;
  updatedBy: string;
}

// ==========================================
// CMS Blog & Media Data Entities
// ==========================================

export type PostStatus = "DRAFT" | "SCHEDULED" | "PUBLISHED" | "ARCHIVED";

export interface BlogAuthor {
  name: string;
  role: string;
  avatarText: string;
  avatarColor: string;
  bio: string;
  profileSlug?: string;
}

export interface BlogSection {
  id: string;
  title: string;
  content: string;
  bulletPoints?: string[];
  table?: {
    headers: string[];
    rows: string[][];
  };
  codeBlock?: {
    language: string;
    code: string;
  };
  callout?: {
    type: "info" | "warning" | "security";
    text: string;
  };
}

export interface PostWorkingDraft {
  title?: string;
  slug?: string;
  excerpt?: string;
  category?: string;
  categoryId?: string;
  authorId?: string;
  author?: BlogAuthor;
  featuredImage?: string | null;
  featuredImageAlt?: string | null;
  featuredImageId?: string | null;
  sections?: BlogSection[];
  contentHtml?: string;
  contentJson?: any;
  readTime?: string;
  wordCount?: number;
  seoTitle?: string | null;
  metaDescription?: string | null;
  canonicalUrl?: string | null;
  robots?: string | null;
  ogTitle?: string | null;
  ogDescription?: string | null;
  ogImage?: string | null;
  ogImageId?: string | null;
  twitterTitle?: string | null;
  twitterDescription?: string | null;
  twitterImage?: string | null;
  twitterImageId?: string | null;
  updatedAt?: string;
  updatedBy?: string;
}

export interface Post {
  id: string;
  slug: string;
  title: string;
  excerpt: string;
  category: string;
  categoryId?: string;
  publishedDate: string;
  readTime: string;
  wordCount?: number;
  featured?: boolean;
  status: PostStatus;
  scheduledFor?: string | null;
  authorId?: string;
  author: BlogAuthor;
  coverGradient: string;
  coverIllustration: string;
  featuredImage?: string | null;
  featuredImageAlt?: string | null;
  featuredImageId?: string | null;
  sections: BlogSection[];
  contentHtml?: string;
  contentJson?: any;
  executiveSummary?: string;
  tableOfContents?: { id: string; title: string }[];
  relatedSlugs: string[];
  keyTakeaways?: string[];
  seoTitle?: string | null;
  metaDescription?: string | null;
  canonicalUrl?: string | null;
  robots?: string | null;
  ogTitle?: string | null;
  ogDescription?: string | null;
  ogImage?: string | null;
  ogImageId?: string | null;
  twitterTitle?: string | null;
  twitterDescription?: string | null;
  twitterImage?: string | null;
  twitterImageId?: string | null;
  workingDraft?: PostWorkingDraft | null;
  hasWorkingDraft?: boolean;
  version: number;
  createdAt: string;
  updatedAt: string;
  createdBy: string;
  updatedBy: string;
}

export interface PostRevision {
  id: string;
  postId: string;
  version: number;
  snapshot: Partial<Post>;
  changeSummary: string;
  actorId: string;
  actorName: string;
  timestamp: string;
}

export interface MediaItem {
  id: string;
  uploadId?: string | null;
  filename: string;
  originalName: string;
  url: string;
  mimeType: string;
  size: number;
  width?: number | null;
  height?: number | null;
  alt: string;
  caption?: string | null;
  usedInPosts: string[];
  uploadedBy: string;
  uploadedAt: string;
  provider?: "cloudinary" | "local";
  publicId?: string | null;
  secureUrl?: string | null;
  resourceType?: string | null;
  format?: string | null;
  bytes?: number | null;
  folder?: string | null;
}

export interface RedirectItem {
  id: string;
  source: string;
  destination: string;
  permanent: boolean;
  method?: 301 | 302 | 307 | 308;
  createdAt: string;
  createdBy: string;
}

export interface CustomRole {
  id: string;
  name: string;
  description: string;
  permissions: string[];
  isSystem?: boolean;
  createdAt: string;
  updatedAt: string;
  createdBy: string;
}

export interface Category {
  id: string;
  name: string;
  slug: string;
  description?: string;
  createdAt: string;
  updatedAt: string;
}

export interface TrustedDevice {
  id: string;
  userId: string;
  tokenHash: string;
  userAgent?: string;
  ipAddress?: string | null;
  createdAt: string;
  expiresAt: string;
  lastUsedAt: string;
}

/** Web Push subscription — stored per browser/device that opted in on the blog. */
export interface WebPushSubscription {
  id: string;
  /** The push service endpoint URL (unique per browser subscription). */
  endpoint: string;
  keys: {
    /** ECDH public key (base64url) */
    p256dh: string;
    /** Authentication secret (base64url) */
    auth: string;
  };
  userAgent: string | null;
  createdAt: string;
}

const DEFAULT_SETTINGS: AdminSettings = {
  require2FAForAllSubAdmins: false,
  sessionTimeoutMinutes: 1440, // 24 hours
  maxLoginAttempts: 5,
  updatedAt: new Date(0).toISOString(),
  updatedBy: "SYSTEM",
};

const SETTINGS_KEY = "singleton";

// ==========================================
// Cryptography Helpers
// ==========================================

export function hashPassword(password: string): { hash: string; salt: string } {
  const salt = crypto.randomBytes(16).toString("hex");
  const hash = crypto.scryptSync(password, salt, 64).toString("hex");
  return { hash, salt };
}

export function verifyPassword(password: string, hash: string, salt: string): boolean {
  try {
    const computed = crypto.scryptSync(password, salt, 64).toString("hex");
    return crypto.timingSafeEqual(Buffer.from(computed, "hex"), Buffer.from(hash, "hex"));
  } catch {
    return false;
  }
}

export function hashPin(pin: string): { hash: string; salt: string } {
  const salt = crypto.randomBytes(16).toString("hex");
  const hash = crypto.scryptSync(pin, salt, 64).toString("hex");
  return { hash, salt };
}

export function verifyPin(pin: string, hash: string, salt: string): boolean {
  try {
    const computed = crypto.scryptSync(pin, salt, 64).toString("hex");
    return crypto.timingSafeEqual(Buffer.from(computed, "hex"), Buffer.from(hash, "hex"));
  } catch {
    return false;
  }
}

export function generateToken(bytes = 32): string {
  return crypto.randomBytes(bytes).toString("hex");
}

export function hashToken(token: string): string {
  return crypto.createHash("sha256").update(token).digest("hex");
}

export function generateTemporaryPassword(): string {
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
  let pass = "";
  for (let i = 0; i < 14; i++) {
    pass += chars.charAt(crypto.randomInt(0, chars.length));
  }
  return `Quto#${pass}`;
}

export interface PasswordResetTokenRecord {
  id: string;
  userId: string;
  email: string;
  tokenHash: string;
  expiresAt: string;
  used: boolean;
  createdAt: string;
}

// ==========================================
// Collections & Indexes
// ==========================================

interface Collections {
  users: Collection<AdminUser>;
  sessions: Collection<AdminSession>;
  resetRequests: Collection<PasswordResetRequest>;
  securityLogs: Collection<SecurityAuditLog>;
  contentLogs: Collection<ContentActivityLog>;
  settings: Collection<AdminSettings & { _id: string }>;
  posts: Collection<Post>;
  revisions: Collection<PostRevision>;
  media: Collection<MediaItem>;
  redirects: Collection<RedirectItem>;
  roles: Collection<CustomRole>;
  categories: Collection<Category>;
  trustedDevices: Collection<TrustedDevice>;
  pushSubscriptions: Collection<WebPushSubscription>;
  passwordResetTokens: Collection<PasswordResetTokenRecord>;
}

let indexesEnsured = false;

async function ensureIndexes(c: Collections): Promise<void> {
  await Promise.all([
    // Auth & Users
    c.users.createIndex({ id: 1 }, { unique: true }),
    c.users.createIndex({ email: 1 }, { unique: true }),
    c.users.createIndex({ authorSlug: 1 }, { unique: true, sparse: true }),
    c.sessions.createIndex({ id: 1 }, { unique: true }),
    c.sessions.createIndex({ tokenHash: 1 }, { unique: true }),
    c.sessions.createIndex({ userId: 1 }),
    c.sessions.createIndex({ userId: 1, status: 1, expiresAt: 1, lastSeenAt: -1 }),
    c.resetRequests.createIndex({ id: 1 }, { unique: true }),
    c.resetRequests.createIndex({ userId: 1, status: 1 }),
    c.passwordResetTokens.createIndex({ id: 1 }, { unique: true }),
    c.passwordResetTokens.createIndex({ tokenHash: 1 }, { unique: true }),
    c.passwordResetTokens.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 }),
    c.securityLogs.createIndex({ id: 1 }, { unique: true }),
    c.securityLogs.createIndex({ timestamp: -1 }),
    c.securityLogs.createIndex({ actorId: 1 }),
    c.securityLogs.createIndex({ targetUserId: 1 }),
    c.securityLogs.createIndex({ action: 1 }),
    c.contentLogs.createIndex({ id: 1 }, { unique: true }),
    c.contentLogs.createIndex({ timestamp: -1 }),
    c.contentLogs.createIndex({ actorId: 1 }),
    c.contentLogs.createIndex({ postId: 1 }),
    // Trusted Devices (2FA)
    c.trustedDevices.createIndex({ id: 1 }, { unique: true }),
    c.trustedDevices.createIndex({ tokenHash: 1 }, { unique: true }),
    c.trustedDevices.createIndex({ userId: 1 }),
    c.trustedDevices.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 }),
    // Web Push Subscriptions
    c.pushSubscriptions.createIndex({ id: 1 }, { unique: true }),
    c.pushSubscriptions.createIndex({ endpoint: 1 }, { unique: true }),
    c.pushSubscriptions.createIndex({ createdAt: -1 }),
    // CMS Posts & Revisions
    c.posts.createIndex({ id: 1 }, { unique: true }),
    c.posts.createIndex({ slug: 1 }, { unique: true }),
    c.posts.createIndex({ status: 1, publishedDate: -1 }),
    c.posts.createIndex({ category: 1 }),
    c.posts.createIndex({ scheduledFor: 1 }),
    c.posts.createIndex({ updatedAt: -1 }),
    c.posts.createIndex({ "author.name": 1 }),
    c.revisions.createIndex({ id: 1 }, { unique: true }),
    c.revisions.createIndex({ postId: 1, version: -1 }),
    // Categories
    c.categories.createIndex({ id: 1 }, { unique: true }),
    c.categories.createIndex({ slug: 1 }, { unique: true }),
    c.categories.createIndex({ name: 1 }, { unique: true }),
    // Media, Redirects & Roles
    c.media.createIndex({ id: 1 }, { unique: true }),
    c.media.createIndex({ uploadId: 1 }, { unique: true, sparse: true }),
    c.media.createIndex({ uploadedAt: -1 }),
    c.redirects.createIndex({ id: 1 }, { unique: true }),
    c.redirects.createIndex({ source: 1 }, { unique: true }),
    c.roles.createIndex({ id: 1 }, { unique: true }),
    c.roles.createIndex({ name: 1 }, { unique: true }),
  ]);
}

async function collections(): Promise<Collections> {
  const database = await getDb();
  const c: Collections = {
    users: database.collection<AdminUser>("admin_users"),
    sessions: database.collection<AdminSession>("admin_sessions"),
    resetRequests: database.collection<PasswordResetRequest>("admin_reset_requests"),
    securityLogs: database.collection<SecurityAuditLog>("admin_security_logs"),
    contentLogs: database.collection<ContentActivityLog>("admin_content_logs"),
    settings: database.collection<AdminSettings & { _id: string }>("admin_settings"),
    posts: database.collection<Post>("posts"),
    revisions: database.collection<PostRevision>("post_revisions"),
    media: database.collection<MediaItem>("media"),
    redirects: database.collection<RedirectItem>("redirects"),
    roles: database.collection<CustomRole>("admin_roles"),
    categories: database.collection<Category>("categories"),
    trustedDevices: database.collection<TrustedDevice>("admin_trusted_devices"),
    pushSubscriptions: database.collection<WebPushSubscription>("push_subscriptions"),
    passwordResetTokens: database.collection<PasswordResetTokenRecord>("admin_password_reset_tokens"),
  };
  if (!indexesEnsured) {
    await ensureIndexes(c);
    indexesEnsured = true;
  }
  return c;
}

const NO_ID = { projection: { _id: 0 } } as const;

// ==========================================
// Database Access Methods (Async MongoDB)
// ==========================================

export const db = {
  // Users
  async getUsers(): Promise<AdminUser[]> {
    const c = await collections();
    return c.users.find({}, NO_ID).sort({ createdAt: 1 }).toArray() as Promise<AdminUser[]>;
  },

  async getUserById(id: string): Promise<AdminUser | null> {
    const c = await collections();
    return c.users.findOne({ id }, NO_ID) as Promise<AdminUser | null>;
  },

  async getUserByEmail(email: string): Promise<AdminUser | null> {
    const normalized = email.trim().toLowerCase();
    const c = await collections();
    const escaped = escapeRegExp(normalized);
    return c.users.findOne(
      { email: { $regex: `^${escaped}$`, $options: "i" } },
      NO_ID
    ) as Promise<AdminUser | null>;
  },

  async getUserByAuthorSlug(slug: string): Promise<AdminUser | null> {
    const c = await collections();
    return c.users.findOne({ authorSlug: slug }, NO_ID) as Promise<AdminUser | null>;
  },

  /**
   * Derives a URL-safe author slug from a base string, ensuring uniqueness
   * across all admin users (excluding the user being updated).
   */
  async generateUniqueAuthorSlug(base: string, excludeUserId?: string): Promise<string> {
    const c = await collections();
    const root =
      base
        .toLowerCase()
        .trim()
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/^-+|-+$/g, "")
        .slice(0, 60) || "author";
    let candidate = root;
    let n = 1;
    // Loop until an unused slug is found (bounded by a sane cap).
    while (n < 1000) {
      const existing = await c.users.findOne({ authorSlug: candidate });
      if (!existing || existing.id === excludeUserId) return candidate;
      n += 1;
      candidate = `${root}-${n}`;
    }
    return `${root}-${crypto.randomUUID().slice(0, 6)}`;
  },

  async createUser(user: AdminUser): Promise<AdminUser> {
    const c = await collections();
    const existing = await this.getUserByEmail(user.email);
    if (existing) {
      throw new Error(`An administrator with email ${user.email} already exists.`);
    }
    await c.users.insertOne({ ...user });
    return user;
  },

  async updateUser(id: string, updates: Partial<AdminUser>): Promise<AdminUser> {
    const c = await collections();
    const existing = await this.getUserById(id);
    if (!existing) throw new Error("User not found");

    if (existing.level === "MAIN_ADMIN" && updates.level && updates.level !== "MAIN_ADMIN") {
      const mainAdmins = await c.users.countDocuments({ level: "MAIN_ADMIN", status: "ACTIVE" });
      if (mainAdmins <= 1) {
        throw new Error("Cannot demote the only remaining active Main Admin.");
      }
    }

    if (existing.level === "MAIN_ADMIN" && updates.status && updates.status !== "ACTIVE") {
      const activeOthers = await c.users.countDocuments({
        id: { $ne: id },
        level: "MAIN_ADMIN",
        status: "ACTIVE",
      });
      if (activeOthers === 0) {
        throw new Error("Cannot deactivate or suspend the only remaining active Main Admin.");
      }
    }

    const merged: AdminUser = {
      ...existing,
      ...updates,
      updatedAt: new Date().toISOString(),
    };

    await c.users.updateOne({ id }, { $set: merged });
    return merged;
  },

  async setUserPin(userId: string, pin: string): Promise<boolean> {
    const c = await collections();
    const { hash, salt } = hashPin(pin);
    const res = await c.users.updateOne(
      { id: userId },
      { $set: { pinHash: hash, pinSalt: salt, pinSetupRequired: false, updatedAt: new Date().toISOString() } }
    );
    return res.modifiedCount > 0;
  },

  async createPasswordResetToken(userId: string, email: string, expiryMinutes = 60): Promise<string> {
    const c = await collections();
    const rawToken = generateToken(32);
    const tokenHash = hashToken(rawToken);
    const now = new Date();
    const expiresAt = new Date(now.getTime() + expiryMinutes * 60 * 1000).toISOString();
    await c.passwordResetTokens.insertOne({
      id: crypto.randomUUID(),
      userId,
      email,
      tokenHash,
      expiresAt,
      used: false,
      createdAt: now.toISOString(),
    });
    return rawToken;
  },

  async verifyPasswordResetToken(rawToken: string): Promise<PasswordResetTokenRecord | null> {
    const c = await collections();
    const tokenHash = hashToken(rawToken);
    const record = await c.passwordResetTokens.findOne({ tokenHash, used: false }, NO_ID);
    if (!record) return null;
    if (new Date(record.expiresAt).getTime() < Date.now()) return null;
    return record;
  },

  async consumePasswordResetToken(rawToken: string): Promise<boolean> {
    const c = await collections();
    const tokenHash = hashToken(rawToken);
    const res = await c.passwordResetTokens.updateOne({ tokenHash }, { $set: { used: true } });
    return res.modifiedCount > 0;
  },

  async addWebAuthnCredential(
    userId: string,
    cred: { id: string; publicKey: string; counter: number; transports?: string[]; createdAt: string }
  ): Promise<boolean> {
    const c = await collections();
    const res = await c.users.updateOne(
      { id: userId },
      { $push: { webauthnCredentials: cred } as any, $set: { updatedAt: new Date().toISOString() } }
    );
    return res.modifiedCount > 0;
  },

  async clearWebAuthnCredentials(userId: string): Promise<boolean> {
    const c = await collections();
    const res = await c.users.updateOne(
      { id: userId },
      { $set: { webauthnCredentials: [], updatedAt: new Date().toISOString() } }
    );
    return res.modifiedCount > 0;
  },

  // Sessions
  async getSessions(): Promise<AdminSession[]> {
    const c = await collections();
    return c.sessions.find({}, NO_ID).toArray() as Promise<AdminSession[]>;
  },

  async getSessionByTokenHash(tokenHash: string): Promise<AdminSession | null> {
    const c = await collections();
    return c.sessions.findOne({ tokenHash, revoked: false }, NO_ID) as Promise<AdminSession | null>;
  },

  /**
   * Retrieves strictly valid, currently active sessions for a user.
   * Automatically reconciles and marks expired any stale sessions exceeding
   * the inactivity threshold or absolute expiration limit.
   */
  async getActiveSessionsForUser(userId: string, inactivityMinutes = 120): Promise<AdminSession[]> {
    const c = await collections();
    const now = new Date();
    const nowIso = now.toISOString();
    const inactivityCutoff = new Date(now.getTime() - inactivityMinutes * 60 * 1000).toISOString();

    // Reconcile and transition stale sessions to EXPIRED
    try {
      await c.sessions.updateMany(
        {
          userId,
          revoked: false,
          $or: [
            { expiresAt: { $lte: nowIso } },
            { lastSeenAt: { $lte: inactivityCutoff } },
            { lastSeenAt: { $exists: false }, lastActiveAt: { $lte: inactivityCutoff } },
          ],
        },
        {
          $set: {
            status: "EXPIRED",
            revoked: true,
            revokedAt: nowIso,
            revokedBy: "SYSTEM",
            revokeReason: "INACTIVITY_TIMEOUT",
          },
        }
      );

      // Normalize legacy unrevoked active records that lack status
      await c.sessions.updateMany(
        {
          userId,
          revoked: false,
          status: { $exists: false },
          expiresAt: { $gt: nowIso },
        },
        {
          $set: { status: "ACTIVE" },
        }
      );
    } catch (reconcileErr) {
      console.warn("[getActiveSessionsForUser] Reconciliation notice:", reconcileErr);
    }

    return c.sessions
      .find(
        {
          userId,
          revoked: false,
          status: "ACTIVE",
          expiresAt: { $gt: nowIso },
          $or: [
            { lastSeenAt: { $gt: inactivityCutoff } },
            { lastSeenAt: { $exists: false }, lastActiveAt: { $gt: inactivityCutoff } },
          ],
        },
        NO_ID
      )
      .sort({ lastSeenAt: -1, createdAt: -1 })
      .toArray() as Promise<AdminSession[]>;
  },

  async createSession(session: AdminSession): Promise<AdminSession> {
    const c = await collections();
    await c.sessions.insertOne({ ...session });
    return session;
  },

  async touchSession(tokenHash: string): Promise<void> {
    const c = await collections();
    const now = new Date().toISOString();
    await c.sessions.updateOne(
      { tokenHash },
      { $set: { lastActiveAt: now, lastSeenAt: now } }
    );
  },

  async lockSession(tokenHash: string): Promise<void> {
    const c = await collections();
    await c.sessions.updateOne(
      { tokenHash },
      { $set: { isLocked: true, lockedAt: new Date().toISOString() } }
    );
  },

  async unlockSession(tokenHash: string): Promise<void> {
    const c = await collections();
    const now = new Date().toISOString();
    await c.sessions.updateOne(
      { tokenHash },
      { $set: { isLocked: false, lockedAt: null, lastActiveAt: now, lastSeenAt: now } }
    );
  },

  async updateSessionLocation(tokenHash: string, location: AuditLocation): Promise<void> {
    const c = await collections();
    await c.sessions.updateOne(
      { tokenHash },
      { $set: { location } }
    );
  },

  async updateSessionNetworkSecurity(tokenHash: string, networkSecurity: NetworkSecurityInfo): Promise<void> {
    const c = await collections();
    await c.sessions.updateOne(
      { tokenHash },
      { $set: { networkSecurity } }
    );
  },

  async revokeSession(tokenHash: string, revokedBy: string, reason = "Session revoked"): Promise<void> {
    const c = await collections();
    const now = new Date().toISOString();
    await c.sessions.updateOne(
      { tokenHash },
      {
        $set: {
          status: "REVOKED",
          revoked: true,
          revokedAt: now,
          revokedBy,
          revokeReason: reason,
        },
      }
    );
  },

  async revokeSessionById(
    sessionId: string,
    userId: string,
    revokedBy: string,
    reason = "Session revoked by administrator"
  ): Promise<boolean> {
    const c = await collections();
    const now = new Date().toISOString();
    const result = await c.sessions.updateOne(
      { id: sessionId, userId, revoked: false },
      {
        $set: {
          status: "REVOKED",
          revoked: true,
          revokedAt: now,
          revokedBy,
          revokeReason: reason,
        },
      }
    );
    return result.modifiedCount > 0;
  },

  async revokeOtherSessions(
    userId: string,
    currentTokenHash: string,
    revokedBy: string,
    reason = "Other sessions revoked by administrator"
  ): Promise<number> {
    const c = await collections();
    const now = new Date().toISOString();
    const result = await c.sessions.updateMany(
      { userId, tokenHash: { $ne: currentTokenHash }, revoked: false },
      {
        $set: {
          status: "REVOKED",
          revoked: true,
          revokedAt: now,
          revokedBy,
          revokeReason: reason,
        },
      }
    );
    return result.modifiedCount;
  },

  async revokeAllSessionsForUser(
    userId: string,
    revokedBy: string,
    reason = "All sessions revoked"
  ): Promise<number> {
    const c = await collections();
    const now = new Date().toISOString();
    const result = await c.sessions.updateMany(
      { userId, revoked: false },
      {
        $set: {
          status: "REVOKED",
          revoked: true,
          revokedAt: now,
          revokedBy,
          revokeReason: reason,
        },
      }
    );
    return result.modifiedCount;
  },

  // Password Reset Requests
  async getResetRequests(): Promise<PasswordResetRequest[]> {
    const c = await collections();
    return c.resetRequests.find({}, NO_ID).sort({ requestedAt: -1 }).toArray() as Promise<
      PasswordResetRequest[]
    >;
  },

  async getPendingResetRequestForUser(userId: string): Promise<PasswordResetRequest | null> {
    const c = await collections();
    const now = new Date().toISOString();
    return c.resetRequests.findOne(
      { userId, status: "PENDING", expiresAt: { $gt: now } },
      NO_ID
    ) as Promise<PasswordResetRequest | null>;
  },

  async createResetRequest(request: PasswordResetRequest): Promise<PasswordResetRequest> {
    const c = await collections();
    await c.resetRequests.updateMany(
      { userId: request.userId, status: "PENDING" },
      { $set: { status: "EXPIRED", handledAt: new Date().toISOString() } }
    );
    await c.resetRequests.insertOne({ ...request });
    return request;
  },

  async updateResetRequest(
    id: string,
    status: ResetRequestStatus,
    handledBy: string,
    reason?: string
  ): Promise<PasswordResetRequest> {
    const c = await collections();
    const existing = (await c.resetRequests.findOne({ id }, NO_ID)) as PasswordResetRequest | null;
    if (!existing) throw new Error("Reset request not found");

    const $set: Record<string, unknown> = {
      status,
      handledAt: new Date().toISOString(),
      handledBy,
    };
    if (reason !== undefined) {
      $set.handlingReason = reason;
    }

    await c.resetRequests.updateOne({ id }, { $set });
    return { ...existing, ...$set } as PasswordResetRequest;
  },

  // Security Audit Logs
  async getSecurityLogs(filters?: {
    action?: string;
    actorId?: string;
    targetUserId?: string;
    search?: string;
    limit?: number;
  }): Promise<SecurityAuditLog[]> {
    const c = await collections();
    const query: Record<string, unknown> = {};

    if (filters?.action) query.action = filters.action;
    if (filters?.actorId) query.actorId = filters.actorId;
    if (filters?.targetUserId) query.targetUserId = filters.targetUserId;
    if (filters?.search) {
      const rx = new RegExp(escapeRegExp(filters.search), "i");
      query.$or = [
        { actorName: rx },
        { actorEmail: rx },
        { targetUserName: rx },
        { targetUserEmail: rx },
        { action: rx },
      ];
    }

    const cursor = c.securityLogs.find(query, NO_ID).sort({ timestamp: -1 });
    if (filters?.limit) cursor.limit(filters.limit);
    return cursor.toArray() as Promise<SecurityAuditLog[]>;
  },

  async logSecurityEvent(
    event: Omit<SecurityAuditLog, "id" | "timestamp">
  ): Promise<SecurityAuditLog> {
    const c = await collections();
    const entry: SecurityAuditLog = {
      ...event,
      id: crypto.randomUUID(),
      timestamp: new Date().toISOString(),
    };
    await c.securityLogs.insertOne({ ...entry });
    return entry;
  },

  async createAuditLog(event: {
    action: SecurityAction;
    status?: "SUCCESS" | "FAILURE";
    userId?: string | null;
    targetType?: string;
    targetId?: string | null;
    details?: Record<string, unknown>;
    location?: AuditLocation | null;
    networkSecurity?: NetworkSecurityInfo | null;
    ipAddress?: string | null;
    ip?: string | null;
    userAgent?: string | null;
    actorId?: string;
    actorName?: string;
    actorEmail?: string;
    actorLevel?: AdminLevel | "SYSTEM";
  }): Promise<SecurityAuditLog> {
    const actorId = event.actorId || event.userId || "SYSTEM";
    let actorName = event.actorName || "Administrator";
    let actorEmail = event.actorEmail || "admin@qutoai.com";
    let actorLevel: AdminLevel | "SYSTEM" = event.actorLevel || "SYSTEM";

    if (event.userId && (!event.actorName || !event.actorEmail)) {
      try {
        const user = await this.getUserById(event.userId);
        if (user) {
          actorName = user.name;
          actorEmail = user.email;
          actorLevel = user.level;
        }
      } catch {}
    }

    return this.logSecurityEvent({
      actorId,
      actorName,
      actorEmail,
      actorLevel,
      targetUserId: event.targetId || null,
      targetUserEmail: null,
      targetUserName: null,
      action: event.action,
      details: {
        ...(event.details || {}),
        status: event.status,
        targetType: event.targetType,
        userAgent: event.userAgent,
      },
      ipAddress: event.ipAddress || event.ip || null,
      location: event.location || null,
      networkSecurity: event.networkSecurity || null,
    });
  },

  // Content Activity Logs
  async getContentLogs(filters?: {
    action?: string;
    actorId?: string;
    postId?: string;
    limit?: number;
  }): Promise<ContentActivityLog[]> {
    const c = await collections();
    const query: Record<string, unknown> = {};

    if (filters?.action && filters.action !== "ALL") {
      if (filters.action === "MEDIA") {
        query.action = { $regex: /^MEDIA_/ };
      } else if (filters.action === "POSTS" || filters.action === "ARTICLES") {
        query.action = { $regex: /^(POST_|TITLE_|SLUG_|SEO_|REVISION_)/ };
      } else if (filters.action === "CATEGORIES") {
        query.action = { $regex: /^CATEGORY_/ };
      } else if (filters.action === "REDIRECTS") {
        query.action = { $regex: /^REDIRECT_/ };
      } else {
        query.action = filters.action;
      }
    }
    if (filters?.actorId) query.actorId = filters.actorId;
    if (filters?.postId) query.postId = filters.postId;

    const cursor = c.contentLogs.find(query, NO_ID).sort({ timestamp: -1 });
    if (filters?.limit) cursor.limit(filters.limit);
    return cursor.toArray() as Promise<ContentActivityLog[]>;
  },

  async logContentEvent(
    event: Omit<ContentActivityLog, "id" | "timestamp">
  ): Promise<ContentActivityLog> {
    const c = await collections();
    const entry: ContentActivityLog = {
      ...event,
      id: crypto.randomUUID(),
      timestamp: new Date().toISOString(),
    };
    await c.contentLogs.insertOne({ ...entry });
    return entry;
  },

  // Settings
  async getSettings(): Promise<AdminSettings> {
    const c = await collections();
    const doc = (await c.settings.findOne({ _id: SETTINGS_KEY }, NO_ID)) as AdminSettings | null;
    return doc ?? { ...DEFAULT_SETTINGS };
  },

  async updateSettings(updates: Partial<AdminSettings>, updatedBy: string): Promise<AdminSettings> {
    const c = await collections();
    const current = (await c.settings.findOne({ _id: SETTINGS_KEY }, NO_ID)) as AdminSettings | null;
    const merged: AdminSettings = {
      ...DEFAULT_SETTINGS,
      ...(current ?? {}),
      ...updates,
      updatedAt: new Date().toISOString(),
      updatedBy,
    };
    await c.settings.updateOne(
      { _id: SETTINGS_KEY },
      { $set: merged },
      { upsert: true }
    );
    return merged;
  },

  // ==========================================
  // Blog Posts CMS Operations
  // ==========================================

  async getPosts(filters?: {
    status?: PostStatus | "ALL";
    category?: string;
    search?: string;
    limit?: number;
    skip?: number;
    sortBy?: "publishedDate" | "updatedAt" | "createdAt" | "title";
    sortOrder?: 1 | -1;
    lean?: boolean;
  }): Promise<Post[]> {
    const c = await collections();
    const query: Record<string, unknown> = {};

    if (filters?.status && filters.status !== "ALL") {
      query.status = filters.status;
    }
    if (filters?.category && filters.category !== "All") {
      query.category = filters.category;
    }
    if (filters?.search && filters.search.trim()) {
      const rx = new RegExp(escapeRegExp(filters.search.trim()), "i");
      query.$or = [
        { title: rx },
        { slug: rx },
        { excerpt: rx },
        { "author.name": rx },
      ];
    }

    const sortField = filters?.sortBy || "publishedDate";
    const sortDir = filters?.sortOrder ?? -1;

    const projection = filters?.lean
      ? { projection: { _id: 0, sections: 0, contentHtml: 0, contentJson: 0 } }
      : NO_ID;

    const cursor = c.posts.find(query, projection).sort({ [sortField]: sortDir });
    if (filters?.skip) cursor.skip(filters.skip);
    if (filters?.limit) cursor.limit(filters.limit);

    return cursor.toArray() as Promise<Post[]>;
  },

  async getPostCount(filters?: {
    status?: PostStatus | "ALL";
    category?: string;
    search?: string;
  }): Promise<number> {
    const c = await collections();
    const query: Record<string, unknown> = {};

    if (filters?.status && filters.status !== "ALL") {
      query.status = filters.status;
    }
    if (filters?.category && filters.category !== "All") {
      query.category = filters.category;
    }
    if (filters?.search && filters.search.trim()) {
      const rx = new RegExp(escapeRegExp(filters.search.trim()), "i");
      query.$or = [
        { title: rx },
        { slug: rx },
        { excerpt: rx },
        { "author.name": rx },
      ];
    }

    return c.posts.countDocuments(query);
  },

  async getPostById(id: string): Promise<Post | null> {
    const c = await collections();
    return c.posts.findOne({ id }, NO_ID) as Promise<Post | null>;
  },

  async getPostBySlug(slug: string): Promise<Post | null> {
    const c = await collections();
    return c.posts.findOne({ slug }, NO_ID) as Promise<Post | null>;
  },

  async createPost(post: Post): Promise<Post> {
    const c = await collections();
    const existing = await c.posts.findOne({ slug: post.slug });
    if (existing) {
      throw new Error(`An article with slug "${post.slug}" already exists.`);
    }
    await c.posts.insertOne({ ...post });
    return post;
  },

  async updatePost(id: string, updates: Partial<Post>): Promise<Post> {
    const c = await collections();
    const existing = await this.getPostById(id);
    if (!existing) throw new Error("Article not found.");

    // If slug is changing, verify uniqueness
    if (updates.slug && updates.slug !== existing.slug) {
      const duplicate = await c.posts.findOne({ slug: updates.slug, id: { $ne: id } });
      if (duplicate) {
        throw new Error(`The slug "${updates.slug}" is already in use by another article.`);
      }
    }

    const merged: Post = {
      ...existing,
      ...updates,
      version: updates.version !== undefined ? updates.version : (existing.version || 1) + 1,
      updatedAt: new Date().toISOString(),
    };

    await c.posts.updateOne({ id }, { $set: merged });
    return merged;
  },

  async deletePost(id: string, force = false): Promise<boolean> {
    const c = await collections();
    const existing = await this.getPostById(id);
    if (!existing) return false;

    // Safety rule: Published posts CANNOT be deleted normally; must be archived
    if (existing.status === "PUBLISHED" && !force) {
      throw new Error("Cannot delete a published article. Please archive it instead to preserve SEO integrity.");
    }

    const res = await c.posts.deleteOne({ id });
    return res.deletedCount > 0;
  },

  // ==========================================
  // Post Revisions
  // ==========================================

  async getRevisions(postId: string): Promise<PostRevision[]> {
    const c = await collections();
    return c.revisions.find({ postId }, NO_ID).sort({ version: -1 }).toArray() as Promise<PostRevision[]>;
  },

  async createRevision(revision: PostRevision): Promise<PostRevision> {
    const c = await collections();
    await c.revisions.insertOne({ ...revision });
    return revision;
  },

  async getRevisionById(id: string): Promise<PostRevision | null> {
    const c = await collections();
    return c.revisions.findOne({ id }, NO_ID) as Promise<PostRevision | null>;
  },

  // ==========================================
  // Media Library
  // ==========================================

  async getMedia(search?: string, limit = 100): Promise<MediaItem[]> {
    const c = await collections();
    const query: Record<string, unknown> = {};
    if (search && search.trim()) {
      const rx = new RegExp(escapeRegExp(search.trim()), "i");
      query.$or = [{ filename: rx }, { originalName: rx }, { alt: rx }, { caption: rx }];
    }
    return c.media.find(query, NO_ID).sort({ uploadedAt: -1 }).limit(limit).toArray() as Promise<MediaItem[]>;
  },

  async getMediaById(id: string): Promise<MediaItem | null> {
    const c = await collections();
    return c.media.findOne({ id }, NO_ID) as Promise<MediaItem | null>;
  },

  async getMediaByUrl(url: string): Promise<MediaItem | null> {
    const c = await collections();
    return c.media.findOne({ url }, NO_ID) as Promise<MediaItem | null>;
  },

  async getMediaByPublicId(publicId: string): Promise<MediaItem | null> {
    const c = await collections();
    return c.media.findOne({ publicId }, NO_ID) as Promise<MediaItem | null>;
  },

  async getMediaByFilename(filename: string): Promise<MediaItem | null> {
    const c = await collections();
    return c.media.findOne({ filename }, NO_ID) as Promise<MediaItem | null>;
  },

  async getMediaByUploadId(uploadId: string): Promise<MediaItem | null> {
    if (!uploadId) return null;
    const c = await collections();
    return c.media.findOne({ uploadId }, NO_ID) as Promise<MediaItem | null>;
  },

  async createMedia(item: MediaItem): Promise<MediaItem> {
    const c = await collections();
    try {
      await c.media.insertOne({ ...item });
      return item;
    } catch (err: any) {
      if (err?.code === 11000 && item.uploadId) {
        const existing = await this.getMediaByUploadId(item.uploadId);
        if (existing) return existing;
      }
      throw err;
    }
  },

  async updateMedia(id: string, updates: Partial<MediaItem>): Promise<MediaItem> {
    const c = await collections();
    const existing = await this.getMediaById(id);
    if (!existing) throw new Error("Media asset not found.");
    const merged = { ...existing, ...updates };
    await c.media.updateOne({ id }, { $set: merged });
    return merged;
  },

  async deleteMedia(id: string): Promise<boolean> {
    const c = await collections();
    const res = await c.media.deleteOne({ id });
    return res.deletedCount > 0;
  },

  // ==========================================
  // Redirects
  // ==========================================

  async getRedirects(): Promise<RedirectItem[]> {
    const c = await collections();
    return c.redirects.find({}, NO_ID).sort({ createdAt: -1 }).toArray() as Promise<RedirectItem[]>;
  },

  async getRedirectBySource(source: string): Promise<RedirectItem | null> {
    const c = await collections();
    return c.redirects.findOne({ source }, NO_ID) as Promise<RedirectItem | null>;
  },

  async createRedirect(item: RedirectItem): Promise<RedirectItem> {
    const c = await collections();
    await c.redirects.updateOne(
      { source: item.source },
      { $set: item },
      { upsert: true }
    );
    return item;
  },

  async deleteRedirect(id: string): Promise<boolean> {
    const c = await collections();
    const res = await c.redirects.deleteOne({ id });
    return res.deletedCount > 0;
  },

  // ==========================================
  // Roles Management
  // ==========================================

  async getRoles(): Promise<CustomRole[]> {
    const c = await collections();
    return c.roles.find({}, NO_ID).sort({ createdAt: 1 }).toArray() as Promise<CustomRole[]>;
  },

  async getRoleById(id: string): Promise<CustomRole | null> {
    const c = await collections();
    return c.roles.findOne({ id }, NO_ID) as Promise<CustomRole | null>;
  },

  async createRole(role: CustomRole): Promise<CustomRole> {
    const c = await collections();
    const existing = await c.roles.findOne({ $or: [{ id: role.id }, { name: role.name }] });
    if (existing) {
      throw new Error(`A role with name "${role.name}" already exists.`);
    }
    await c.roles.insertOne({ ...role });
    return role;
  },

  async updateRole(id: string, updates: Partial<CustomRole>): Promise<CustomRole> {
    const c = await collections();
    const existing = await this.getRoleById(id);
    if (!existing) throw new Error("Role not found.");
    if (existing.isSystem) throw new Error("System roles cannot be modified.");

    const merged: CustomRole = {
      ...existing,
      ...updates,
      updatedAt: new Date().toISOString(),
    };
    await c.roles.updateOne({ id }, { $set: merged });
    return merged;
  },

  async deleteRole(id: string): Promise<boolean> {
    const c = await collections();
    const existing = await this.getRoleById(id);
    if (!existing) throw new Error("Role not found.");
    if (existing.isSystem) throw new Error("System roles cannot be deleted.");

    // Check if any admin currently uses this role
    const assignedCount = await c.users.countDocuments({ role: id as any });
    if (assignedCount > 0) {
      throw new Error(`Cannot delete role: ${assignedCount} administrator(s) are currently assigned to it. Reassign them first.`);
    }

    const res = await c.roles.deleteOne({ id });
    return res.deletedCount > 0;
  },

  // ==========================================
  // Categories Management
  // ==========================================

  async getCategories(): Promise<Category[]> {
    const c = await collections();
    let items = (await c.categories.find({}, NO_ID).sort({ name: 1 }).toArray()) as Category[];
    if (items.length === 0) {
      const now = new Date().toISOString();
      const defaultCategories: Category[] = [
        { id: "cat-1", name: "Pricing & Reviews", slug: "pricing-reviews", description: "Detailed pricing reviews, cost analyses, and ROI calculators for conversational voice AI solutions.", createdAt: now, updatedAt: now },
        { id: "cat-2", name: "Company Updates", slug: "company-updates", description: "Read company announcements, product releases, fundraising milestones, and updates from the team.", createdAt: now, updatedAt: now },
        { id: "cat-3", name: "Voice AI Guides", slug: "voice-ai-guides", description: "Comprehensive engineering guides, SIP architecture, and deployment strategies for enterprise voice AI.", createdAt: now, updatedAt: now },
        { id: "cat-4", name: "Tool Comparisons", slug: "tool-comparisons", description: "In-depth evaluations, feature comparisons, and pricing breakdowns of leading voice AI platforms and alternatives.", createdAt: now, updatedAt: now },
        { id: "cat-5", name: "AI Use Cases", slug: "ai-use-cases", description: "Explore practical AI use cases for sales, support, call centers, ecommerce, and customer operations, with guides on using voice AI to automate workflows.", createdAt: now, updatedAt: now },
      ];
      await c.categories.insertMany(defaultCategories as any);
      items = defaultCategories;
    }
    return items;
  },

  async getCategoryById(id: string): Promise<Category | null> {
    const c = await collections();
    return c.categories.findOne({ id }, NO_ID) as Promise<Category | null>;
  },

  async getCategoryBySlug(slug: string): Promise<Category | null> {
    const c = await collections();
    return c.categories.findOne({ slug }, NO_ID) as Promise<Category | null>;
  },

  async createCategory(cat: Omit<Category, "id" | "createdAt" | "updatedAt">): Promise<Category> {
    const c = await collections();
    const existing = await c.categories.findOne({ $or: [{ slug: cat.slug }, { name: cat.name }] });
    if (existing) {
      throw new Error(`A category with name "${cat.name}" or slug "${cat.slug}" already exists.`);
    }
    const now = new Date().toISOString();
    const newCategory: Category = {
      id: crypto.randomUUID(),
      name: cat.name.trim(),
      slug: cat.slug.trim().toLowerCase(),
      description: cat.description?.trim() || "",
      createdAt: now,
      updatedAt: now,
    };
    await c.categories.insertOne({ ...newCategory });
    return newCategory;
  },

  async updateCategory(id: string, updates: Partial<Category>): Promise<Category> {
    const c = await collections();
    const existing = await this.getCategoryById(id);
    if (!existing) throw new Error("Category not found.");

    if (updates.slug && updates.slug !== existing.slug) {
      const conflict = await c.categories.findOne({ slug: updates.slug, id: { $ne: id } });
      if (conflict) throw new Error(`Slug "${updates.slug}" is already taken.`);
    }

    const merged: Category = {
      ...existing,
      ...updates,
      updatedAt: new Date().toISOString(),
    };
    await c.categories.updateOne({ id }, { $set: merged });
    return merged;
  },

  async deleteCategory(id: string): Promise<boolean> {
    const c = await collections();
    const existing = await this.getCategoryById(id);
    if (!existing) throw new Error("Category not found.");

    const count = await c.posts.countDocuments({ category: existing.name });
    if (count > 0) {
      throw new Error(`Cannot delete category: ${count} article(s) are using it.`);
    }

    const res = await c.categories.deleteOne({ id });
    return res.deletedCount > 0;
  },

  // ==========================================
  // Trusted Devices (2FA - 30 Days)
  // ==========================================

  async createTrustedDevice(data: {
    userId: string;
    token: string;
    userAgent?: string;
    ipAddress?: string | null;
  }): Promise<TrustedDevice> {
    const c = await collections();
    const tokenHash = hashToken(data.token);
    const now = new Date();
    const expiresAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString();
    const device: TrustedDevice = {
      id: crypto.randomUUID(),
      userId: data.userId,
      tokenHash,
      userAgent: data.userAgent || "",
      ipAddress: data.ipAddress || null,
      createdAt: now.toISOString(),
      expiresAt,
      lastUsedAt: now.toISOString(),
    };
    await c.trustedDevices.insertOne({ ...device });
    return device;
  },

  async verifyTrustedDevice(userId: string, token: string): Promise<boolean> {
    if (!userId || !token) return false;
    const c = await collections();
    const tokenHash = hashToken(token);
    const device = await c.trustedDevices.findOne({ userId, tokenHash });
    if (!device) return false;
    if (new Date(device.expiresAt).getTime() < Date.now()) {
      await c.trustedDevices.deleteOne({ id: device.id });
      return false;
    }
    await c.trustedDevices.updateOne({ id: device.id }, { $set: { lastUsedAt: new Date().toISOString() } });
    return true;
  },

  async revokeTrustedDevice(id: string): Promise<boolean> {
    const c = await collections();
    const res = await c.trustedDevices.deleteOne({ id });
    return res.deletedCount > 0;
  },

  async revokeAllUserTrustedDevices(userId: string): Promise<number> {
    const c = await collections();
    const res = await c.trustedDevices.deleteMany({ userId });
    return res.deletedCount;
  },

  // ==========================================
  // Web Push Subscriptions
  // ==========================================

  async savePushSubscription(
    data: Pick<WebPushSubscription, "endpoint" | "keys" | "userAgent">
  ): Promise<WebPushSubscription> {
    const c = await collections();
    const now = new Date().toISOString();
    const sub: WebPushSubscription = {
      id: crypto.randomUUID(),
      endpoint: data.endpoint,
      keys: data.keys,
      userAgent: data.userAgent || null,
      createdAt: now,
    };
    // Upsert by endpoint: update if exists, insert if new
    await c.pushSubscriptions.updateOne(
      { endpoint: data.endpoint },
      { $set: sub },
      { upsert: true }
    );
    return sub;
  },

  async deletePushSubscription(endpoint: string): Promise<boolean> {
    const c = await collections();
    const res = await c.pushSubscriptions.deleteOne({ endpoint });
    return res.deletedCount > 0;
  },

  async getAllPushSubscriptions(): Promise<WebPushSubscription[]> {
    const c = await collections();
    return c.pushSubscriptions
      .find({}, NO_ID)
      .sort({ createdAt: -1 })
      .toArray() as Promise<WebPushSubscription[]>;
  },

  async countPushSubscriptions(): Promise<number> {
    const c = await collections();
    return c.pushSubscriptions.countDocuments();
  },
};

function escapeRegExp(input: string): string {
  return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
