/**
 * Auto-Registration — zero-touch product provisioning.
 *
 * When a request arrives with an unknown productId AND a valid JWT,
 * auto-create a minimal ProductDoc instead of rejecting the request.
 * This enables new products to start using platform-service immediately
 * without manual admin setup.
 *
 * Security:
 *  - Requires valid JWT (unauthenticated requests still rejected)
 *  - Rate-limited: max 10 auto-registrations per minute
 *  - productId must match /^[a-z0-9_-]+$/ (same as CreateProductSchema)
 *  - Audit-logged as `product.auto_registered`
 */

import * as productRepo from '../modules/products/repository.js';
import { loadProductCache } from '../modules/products/cache.js';
import * as auditRepo from '../modules/audit/repository.js';
import type { ProductDoc } from '../modules/products/types.js';

const PRODUCT_ID_PATTERN = /^[a-z0-9_-]+$/;
const MAX_PRODUCT_ID_LENGTH = 64;

// ── Rate limiter (sliding window, in-process) ───────────────────

const RATE_LIMIT_WINDOW_MS = 60_000; // 1 minute
const RATE_LIMIT_MAX = 10;
const registrationTimestamps: number[] = [];

function isRateLimited(): boolean {
  const now = Date.now();
  // Prune expired entries
  while (
    registrationTimestamps.length > 0 &&
    registrationTimestamps[0]! < now - RATE_LIMIT_WINDOW_MS
  ) {
    registrationTimestamps.shift();
  }
  return registrationTimestamps.length >= RATE_LIMIT_MAX;
}

function recordRegistration(): void {
  registrationTimestamps.push(Date.now());
}

/** Reset rate limiter (for testing). */
export function resetRateLimiter(): void {
  registrationTimestamps.length = 0;
}

// ── Auto-Registration ───────────────────────────────────────────

export interface AutoRegisterResult {
  registered: boolean;
  product?: ProductDoc;
  reason?: string;
}

/**
 * Attempt to auto-register an unknown productId.
 *
 * @param productId  The unknown product identifier
 * @param userId     The authenticated user's ID (from JWT)
 * @returns Result indicating whether registration succeeded
 */
export async function autoRegisterProduct(
  productId: string,
  userId: string
): Promise<AutoRegisterResult> {
  // Validate productId format
  if (
    !productId ||
    productId.length > MAX_PRODUCT_ID_LENGTH ||
    !PRODUCT_ID_PATTERN.test(productId)
  ) {
    return { registered: false, reason: 'Invalid productId format' };
  }

  // Rate limit check
  if (isRateLimited()) {
    return { registered: false, reason: 'Auto-registration rate limit exceeded' };
  }

  // Double-check it doesn't already exist (race condition guard)
  const existing = await productRepo.getById(productId);
  if (existing) {
    // Already exists — just refresh cache and proceed
    await loadProductCache();
    return { registered: false, product: existing, reason: 'Already exists' };
  }

  // Build minimal product doc
  const now = new Date().toISOString();
  const displayName = productId.replace(/[-_]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
  const licensePrefix = productId.replace(/[-_]/g, '').slice(0, 8).toUpperCase() || 'PROD';

  const doc: ProductDoc = {
    id: productId,
    productId,
    displayName,
    licensePrefix,
    packageName: '',
    defaultPlan: 'free',
    trialDays: 14,
    deviceLimits: { free: 1, pro: 3, enterprise: 10 },
    websiteUrl: '',
    status: 'active',
    ownerId: userId,
    createdAt: now,
    updatedAt: now,
  };

  try {
    const created = await productRepo.create(doc);
    await loadProductCache();
    recordRegistration();

    // Audit log (best-effort — don't fail if audit write fails)
    try {
      await auditRepo.create({
        id: `audit_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
        productId,
        userId,
        action: 'product.auto_registered',
        category: 'product',
        details: {
          displayName: created.displayName,
          registeredBy: userId,
          method: 'auto-registration',
        },
        createdAt: now,
      });
    } catch {
      // Best-effort audit
    }

    return { registered: true, product: created };
  } catch (err) {
    // If create fails due to conflict (race), treat as success
    const message = err instanceof Error ? err.message : 'Unknown error';
    if (message.includes('Conflict') || message.includes('409')) {
      await loadProductCache();
      return { registered: false, reason: 'Concurrent registration' };
    }
    return { registered: false, reason: message };
  }
}
