/**
 * API token repository — cloud-agnostic via @bytelyst/datastore.
 */

import bcrypt from 'bcryptjs';
import { getCollection } from '../../lib/datastore.js';
import type { ApiTokenDoc, ApiTokenResponse } from './types.js';

function collection() {
  return getCollection<ApiTokenDoc>('api_tokens', '/id');
}

function stripHash(doc: ApiTokenDoc): ApiTokenResponse {
  const { tokenHash: _hash, ...rest } = doc;
  void _hash;
  return rest;
}

export async function list(productId: string, limit = 100): Promise<ApiTokenResponse[]> {
  const results = await collection().findMany({
    filter: { productId, status: { $ne: 'expired' } },
    sort: { createdAt: -1 },
    limit,
  });
  return results.map(stripHash);
}

export async function listByUser(userId: string, productId: string): Promise<ApiTokenResponse[]> {
  const results = await collection().findMany({
    filter: { productId, userId },
    sort: { createdAt: -1 },
  });
  return results.map(stripHash);
}

export async function getById(id: string): Promise<ApiTokenDoc | null> {
  try {
    return await collection().findById(id, id);
  } catch {
    return null;
  }
}

export async function create(doc: ApiTokenDoc): Promise<ApiTokenResponse> {
  const created = await collection().create(doc);
  return stripHash(created);
}

export async function revoke(id: string, productId?: string): Promise<boolean> {
  const existing = await getById(id);
  if (!existing || (productId && existing.productId !== productId)) return false;

  await collection().update(id, id, { status: 'revoked' } as Partial<ApiTokenDoc>);
  return true;
}

export async function remove(id: string, productId?: string): Promise<boolean> {
  try {
    const existing = await getById(id);
    if (!existing || (productId && existing.productId !== productId)) return false;
    await collection().delete(id, id);
    return true;
  } catch {
    return false;
  }
}

export async function countActive(productId: string): Promise<number> {
  return collection().count({ productId, status: 'active' });
}

export async function hashToken(raw: string): Promise<string> {
  return bcrypt.hash(raw, 10);
}
