import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { v4 as uuidv4 } from "uuid";
import * as bcrypt from "bcryptjs";
import { logger } from "../core/monitoring/logger.js";
class UserModel {
  db;
  constructor(db) {
    this.db = db;
    this.initialize();
  }
  initialize() {
    this.db.exec(`
      CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY,
        sub TEXT UNIQUE NOT NULL,
        email TEXT UNIQUE NOT NULL,
        name TEXT,
        avatar TEXT,
        tier TEXT DEFAULT 'free',
        permissions TEXT DEFAULT '["read", "write"]',
        organizations TEXT DEFAULT '[]',
        api_keys TEXT DEFAULT '[]',
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        last_login_at DATETIME,
        metadata TEXT DEFAULT '{}'
      )
    `);
    this.db.exec(`
      CREATE TABLE IF NOT EXISTS user_sessions (
        id TEXT PRIMARY KEY,
        user_id TEXT NOT NULL,
        token TEXT UNIQUE NOT NULL,
        expires_at DATETIME NOT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        metadata TEXT DEFAULT '{}',
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
      )
    `);
    this.db.exec(`
      CREATE TABLE IF NOT EXISTS api_keys (
        id TEXT PRIMARY KEY,
        user_id TEXT NOT NULL,
        key_hash TEXT UNIQUE NOT NULL,
        name TEXT,
        last_used_at DATETIME,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        expires_at DATETIME,
        metadata TEXT DEFAULT '{}',
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
      )
    `);
    this.db.exec(`
      CREATE INDEX IF NOT EXISTS idx_users_sub ON users(sub);
      CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
      CREATE INDEX IF NOT EXISTS idx_sessions_token ON user_sessions(token);
      CREATE INDEX IF NOT EXISTS idx_sessions_user ON user_sessions(user_id);
      CREATE INDEX IF NOT EXISTS idx_sessions_expires ON user_sessions(expires_at);
      CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);
      CREATE INDEX IF NOT EXISTS idx_api_keys_user ON api_keys(user_id);
    `);
    logger.info("User database schema initialized");
  }
  async createUser(userData) {
    if (!userData.sub || !userData.email) {
      throw new Error("User sub and email are required");
    }
    const user = {
      id: userData.id || uuidv4(),
      sub: userData.sub,
      email: userData.email,
      name: userData.name,
      avatar: userData.avatar,
      tier: userData.tier || "free",
      permissions: userData.permissions || ["read", "write"],
      organizations: userData.organizations || [],
      apiKeys: userData.apiKeys || [],
      createdAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date(),
      metadata: userData.metadata || {}
    };
    const stmt = this.db.prepare(`
      INSERT INTO users (
        id, sub, email, name, avatar, tier, permissions, 
        organizations, api_keys, created_at, updated_at, metadata
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);
    stmt.run(
      user.id,
      user.sub,
      user.email,
      user.name,
      user.avatar,
      user.tier,
      JSON.stringify(user.permissions),
      JSON.stringify(user.organizations),
      JSON.stringify(user.apiKeys),
      user.createdAt.toISOString(),
      user.updatedAt.toISOString(),
      JSON.stringify(user.metadata)
    );
    logger.info("User created", { userId: user.id, email: user.email });
    return user;
  }
  async findUserBySub(sub) {
    const stmt = this.db.prepare("SELECT * FROM users WHERE sub = ?");
    const row = stmt.get(sub);
    if (!row) {
      return null;
    }
    return this.rowToUser(row);
  }
  async findUserByEmail(email) {
    const stmt = this.db.prepare("SELECT * FROM users WHERE email = ?");
    const row = stmt.get(email);
    if (!row) {
      return null;
    }
    return this.rowToUser(row);
  }
  async findUserById(id) {
    const stmt = this.db.prepare("SELECT * FROM users WHERE id = ?");
    const row = stmt.get(id);
    if (!row) {
      return null;
    }
    return this.rowToUser(row);
  }
  async updateUser(id, updates) {
    const user = await this.findUserById(id);
    if (!user) {
      return null;
    }
    const updatedUser = {
      ...user,
      ...updates,
      updatedAt: /* @__PURE__ */ new Date()
    };
    const stmt = this.db.prepare(`
      UPDATE users SET
        email = ?, name = ?, avatar = ?, tier = ?, 
        permissions = ?, organizations = ?, api_keys = ?,
        updated_at = ?, last_login_at = ?, metadata = ?
      WHERE id = ?
    `);
    stmt.run(
      updatedUser.email,
      updatedUser.name,
      updatedUser.avatar,
      updatedUser.tier,
      JSON.stringify(updatedUser.permissions),
      JSON.stringify(updatedUser.organizations),
      JSON.stringify(updatedUser.apiKeys),
      updatedUser.updatedAt.toISOString(),
      updatedUser.lastLoginAt?.toISOString(),
      JSON.stringify(updatedUser.metadata),
      id
    );
    logger.info("User updated", { userId: id });
    return updatedUser;
  }
  async deleteUser(id) {
    const stmt = this.db.prepare("DELETE FROM users WHERE id = ?");
    const result = stmt.run(id);
    if (result.changes > 0) {
      logger.info("User deleted", { userId: id });
      return true;
    }
    return false;
  }
  async updateLastLogin(id) {
    const stmt = this.db.prepare(
      "UPDATE users SET last_login_at = ? WHERE id = ?"
    );
    stmt.run((/* @__PURE__ */ new Date()).toISOString(), id);
  }
  // Session management
  async createSession(userId, expiresIn = 86400) {
    const session = {
      id: uuidv4(),
      userId,
      token: this.generateSessionToken(),
      expiresAt: new Date(Date.now() + expiresIn * 1e3),
      createdAt: /* @__PURE__ */ new Date(),
      metadata: {}
    };
    const stmt = this.db.prepare(`
      INSERT INTO user_sessions (id, user_id, token, expires_at, created_at, metadata)
      VALUES (?, ?, ?, ?, ?, ?)
    `);
    stmt.run(
      session.id,
      session.userId,
      session.token,
      session.expiresAt.toISOString(),
      session.createdAt.toISOString(),
      JSON.stringify(session.metadata)
    );
    logger.info("Session created", { sessionId: session.id, userId });
    return session;
  }
  async findSessionByToken(token) {
    const stmt = this.db.prepare("SELECT * FROM user_sessions WHERE token = ?");
    const row = stmt.get(token);
    if (!row) {
      return null;
    }
    return this.rowToSession(row);
  }
  async validateSession(token) {
    const session = await this.findSessionByToken(token);
    if (!session) {
      return null;
    }
    if (new Date(session.expiresAt) < /* @__PURE__ */ new Date()) {
      await this.deleteSession(session.id);
      return null;
    }
    return await this.findUserById(session.userId);
  }
  async deleteSession(id) {
    const stmt = this.db.prepare("DELETE FROM user_sessions WHERE id = ?");
    const result = stmt.run(id);
    return result.changes > 0;
  }
  async deleteExpiredSessions() {
    const stmt = this.db.prepare(
      "DELETE FROM user_sessions WHERE expires_at < ?"
    );
    const result = stmt.run((/* @__PURE__ */ new Date()).toISOString());
    if (result.changes > 0) {
      logger.info("Expired sessions deleted", { count: result.changes });
    }
    return result.changes;
  }
  // API Key management
  async generateApiKey(userId, name) {
    const user = await this.findUserById(userId);
    if (!user) {
      throw new Error("User not found");
    }
    const apiKey = `sk-${this.generateToken(32)}`;
    const hashedKey = await bcrypt.hash(apiKey, 10);
    const stmt = this.db.prepare(`
      INSERT INTO api_keys (id, user_id, key_hash, name, created_at)
      VALUES (?, ?, ?, ?, ?)
    `);
    const apiKeyId = uuidv4();
    stmt.run(
      apiKeyId,
      userId,
      hashedKey,
      name || "API Key",
      (/* @__PURE__ */ new Date()).toISOString()
    );
    logger.info("API key generated", { userId, apiKeyId });
    return apiKey;
  }
  async validateApiKey(apiKey) {
    const stmt = this.db.prepare(`
      SELECT u.*, ak.id as api_key_id, ak.key_hash
      FROM api_keys ak
      JOIN users u ON ak.user_id = u.id
      WHERE (ak.expires_at IS NULL OR ak.expires_at > datetime('now'))
    `);
    const rows = stmt.all();
    for (const row of rows) {
      if (await bcrypt.compare(apiKey, row.key_hash)) {
        const updateStmt = this.db.prepare(
          "UPDATE api_keys SET last_used_at = ? WHERE id = ?"
        );
        updateStmt.run((/* @__PURE__ */ new Date()).toISOString(), row.api_key_id);
        return this.rowToUser(row);
      }
    }
    return null;
  }
  async revokeApiKey(userId, apiKeyId) {
    const stmt = this.db.prepare(
      "DELETE FROM api_keys WHERE id = ? AND user_id = ?"
    );
    const result = stmt.run(apiKeyId, userId);
    if (result.changes > 0) {
      logger.info("API key revoked", { userId, apiKeyId });
      return true;
    }
    return false;
  }
  async listApiKeys(userId) {
    const stmt = this.db.prepare(`
      SELECT id, name, last_used_at, created_at
      FROM api_keys
      WHERE user_id = ?
      ORDER BY created_at DESC
    `);
    const rows = stmt.all(userId);
    return rows.map((row) => ({
      id: row.id,
      name: row.name,
      lastUsed: row.last_used_at ? new Date(row.last_used_at) : void 0,
      createdAt: new Date(row.created_at)
    }));
  }
  // Helper methods
  rowToUser(row) {
    return {
      id: row.id,
      sub: row.sub,
      email: row.email,
      name: row.name,
      avatar: row.avatar,
      tier: row.tier,
      permissions: JSON.parse(row.permissions),
      organizations: JSON.parse(row.organizations),
      apiKeys: JSON.parse(row.api_keys || "[]"),
      createdAt: new Date(row.created_at),
      updatedAt: new Date(row.updated_at),
      lastLoginAt: row.last_login_at ? new Date(row.last_login_at) : void 0,
      metadata: JSON.parse(row.metadata || "{}")
    };
  }
  rowToSession(row) {
    return {
      id: row.id,
      userId: row.user_id,
      token: row.token,
      expiresAt: new Date(row.expires_at),
      createdAt: new Date(row.created_at),
      metadata: JSON.parse(row.metadata || "{}")
    };
  }
  generateSessionToken() {
    return this.generateToken(48);
  }
  generateToken(length) {
    const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    let token = "";
    for (let i = 0; i < length; i++) {
      token += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return token;
  }
}
let userModelInstance = null;
function getUserModel(db) {
  if (!userModelInstance) {
    userModelInstance = new UserModel(db);
  }
  return userModelInstance;
}
export {
  UserModel,
  getUserModel
};
//# sourceMappingURL=user.model.js.map
