import { queryOne } from "../db";
import { ApiKeyManager } from "./keys";
import { apiKeyCache, getCacheKey } from "./cache";
function hasScope(auth, requiredScope) {
  return auth.scopes.includes(requiredScope);
}
async function validateApiKey(request) {
  const startTime = Date.now();
  try {
    const authHeader = request.headers.get("Authorization");
    const xApiKeyHeader = request.headers.get("x-api-key");
    let apiKey = null;
    if (authHeader == null ? void 0 : authHeader.startsWith("Bearer ")) {
      apiKey = authHeader.substring(7);
    } else if (xApiKeyHeader) {
      apiKey = xApiKeyHeader;
    }
    if (!apiKey) {
      await constantTimeDelay(startTime);
      return null;
    }
    if (!ApiKeyManager.validateKeyFormat(apiKey)) {
      await constantTimeDelay(startTime);
      return null;
    }
    const prefix = ApiKeyManager.extractPrefix(apiKey);
    const keyHash = await ApiKeyManager.hashKey(apiKey);
    const cacheKey = getCacheKey("api_key", keyHash);
    let keyData = apiKeyCache.get(cacheKey);
    if (!keyData) {
      const dbResult = await queryOne(
        `SELECT id, "userId", scopes, status, "expiresAt", "failedAttempts", "lockedUntil"
         FROM "api_key" 
         WHERE "keyHash" = $1 AND "keyPrefix" = $2`,
        [keyHash, prefix]
      );
      if (dbResult) {
        keyData = {
          id: dbResult.id,
          userId: dbResult.userId,
          scopes: dbResult.scopes,
          status: dbResult.status,
          expiresAt: dbResult.expiresAt,
          failedAttempts: dbResult.failedAttempts,
          lockedUntil: dbResult.lockedUntil
        };
        apiKeyCache.set(cacheKey, keyData, 3e5);
      }
    }
    if (!keyData) {
      await constantTimeDelay(startTime);
      return null;
    }
    if (keyData.lockedUntil && new Date(keyData.lockedUntil) > /* @__PURE__ */ new Date()) {
      await constantTimeDelay(startTime);
      return null;
    }
    if (keyData.status !== "active") {
      await constantTimeDelay(startTime);
      return null;
    }
    if (keyData.expiresAt && new Date(keyData.expiresAt) < /* @__PURE__ */ new Date()) {
      markAsExpired(keyData.id).catch(console.error);
      await constantTimeDelay(startTime);
      return null;
    }
    if (keyData.failedAttempts && keyData.failedAttempts > 0) {
      resetFailedAttempts(keyData.id).catch(console.error);
    }
    updateLastUsed(keyData.id).catch((error) => {
      console.error("Error updating API key last used:", error);
    });
    return {
      userId: keyData.userId,
      keyId: keyData.id,
      scopes: keyData.scopes || []
    };
  } catch (error) {
    console.error("Error validating API key:", error);
    await constantTimeDelay(startTime);
    return null;
  }
}
async function constantTimeDelay(startTime) {
  const minDelay = 100;
  const elapsed = Date.now() - startTime;
  const remaining = Math.max(0, minDelay - elapsed);
  if (remaining > 0) {
    await new Promise((resolve) => setTimeout(resolve, remaining));
  }
}
async function resetFailedAttempts(keyId) {
  try {
    await queryOne(
      'UPDATE "api_key" SET "failedAttempts" = 0, "lockedUntil" = NULL WHERE id = $1',
      [keyId]
    );
  } catch (error) {
    console.error("Failed to reset failed attempts:", error);
  }
}
async function markAsExpired(keyId) {
  try {
    await queryOne(
      'UPDATE "api_key" SET status = $1 WHERE id = $2',
      ["expired", keyId]
    );
    const cacheKey = getCacheKey("api_key", keyId);
    apiKeyCache.delete(cacheKey);
  } catch (error) {
    console.error("Failed to mark API key as expired:", error);
  }
}
function hasAnyScope(auth, requiredScopes) {
  if (auth.scopes.includes("*")) {
    return true;
  }
  return requiredScopes.some((scope) => auth.scopes.includes(scope));
}
function hasAllScopes(auth, requiredScopes) {
  if (auth.scopes.includes("*")) {
    return true;
  }
  return requiredScopes.every((scope) => auth.scopes.includes(scope));
}
async function updateLastUsed(keyId) {
  try {
    await queryOne(
      'UPDATE "api_key" SET "lastUsedAt" = CURRENT_TIMESTAMP WHERE id = $1',
      [keyId]
    );
  } catch (error) {
    console.error("Failed to update API key last used timestamp:", error);
  }
}
async function getApiKeyUser(auth) {
  try {
    const user = await queryOne(
      'SELECT id, email, "firstName", "lastName", role FROM "users" WHERE id = $1',
      [auth.userId]
    );
    return user;
  } catch (error) {
    console.error("Error fetching API key user:", error);
    return null;
  }
}
async function canCreateApiKeys(userId) {
  try {
    const user = await queryOne(
      'SELECT role FROM "users" WHERE id = $1',
      [userId]
    );
    if (!user) {
      return false;
    }
    return ["admin", "superadmin"].includes(user.role);
  } catch (error) {
    console.error("Error checking API key creation permissions:", error);
    return false;
  }
}
async function validateScopesForUser(userId, requestedScopes) {
  try {
    const user = await queryOne(
      'SELECT role FROM "users" WHERE id = $1',
      [userId]
    );
    if (!user) {
      return {
        valid: false,
        allowedScopes: [],
        deniedScopes: requestedScopes
      };
    }
    const scopesByRole = {
      member: ["tasks:read", "tasks:write"],
      colaborator: ["tasks:read", "tasks:write", "tasks:delete", "users:read"],
      admin: [
        "users:read",
        "users:write",
        "users:delete",
        "tasks:read",
        "tasks:write",
        "tasks:delete",
        "admin:api-keys",
        "admin:users"
      ],
      superadmin: ["*"]
      // Acceso completo
    };
    const allowedScopes = scopesByRole[user.role] || [];
    if (allowedScopes.includes("*")) {
      return {
        valid: true,
        allowedScopes: requestedScopes,
        deniedScopes: []
      };
    }
    const validScopes = requestedScopes.filter((scope) => allowedScopes.includes(scope));
    const deniedScopes = requestedScopes.filter((scope) => !allowedScopes.includes(scope));
    return {
      valid: deniedScopes.length === 0,
      allowedScopes: validScopes,
      deniedScopes
    };
  } catch (error) {
    console.error("Error validating scopes for user:", error);
    return {
      valid: false,
      allowedScopes: [],
      deniedScopes: requestedScopes
    };
  }
}
export {
  canCreateApiKeys,
  getApiKeyUser,
  hasAllScopes,
  hasAnyScope,
  hasScope,
  validateApiKey,
  validateScopesForUser
};
