import { NextRequest, NextResponse } from 'next/server';
import { getSupabaseAdmin, hashKey } from '@/lib/supabase';
import { createReadStream, existsSync, statSync } from 'fs';

// 5 downloads per hour per IP
const ipWindows = new Map<string, { count: number; resetAt: number }>();
function checkLimit(ip: string): boolean {
  const now = Date.now();
  const win = ipWindows.get(ip);
  if (!win || now > win.resetAt) {
    ipWindows.set(ip, { count: 1, resetAt: now + 3_600_000 });
    return true;
  }
  if (win.count >= 5) return false;
  win.count++;
  return true;
}

// GET /api/download?key=LAU-XXXX-XXXX-XXXX
export async function GET(req: NextRequest) {
  const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? '0.0.0.0';
  if (!checkLimit(ip)) {
    return NextResponse.json({ error: 'rate_limit' }, { status: 429 });
  }

  const key = req.nextUrl.searchParams.get('key') ?? '';
  if (!key.match(/^LAU-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/)) {
    return NextResponse.json({ error: 'invalid_key' }, { status: 400 });
  }

  const keyHash = hashKey(key);
  const { data } = await getSupabaseAdmin()
    .from('licences')
    .select('active')
    .eq('key_hash', keyHash)
    .single();
  const licence = data as { active: boolean } | null;

  if (!licence?.active) {
    return NextResponse.json({ error: 'licence_invalid' }, { status: 401 });
  }

  const zipPath = process.env.MODULE_ZIP_PATH ?? '/var/www/html/claude-rep/dolibarr-ia/dist/module_notetoquote-1.0.0.zip';
  if (!existsSync(zipPath)) {
    return NextResponse.json({ error: 'zip_not_found' }, { status: 500 });
  }

  const filename = zipPath.split('/').pop() ?? 'module_notetoquote-1.0.0.zip';
  const { size } = statSync(zipPath);
  const nodeStream = createReadStream(zipPath);
  const webStream = new ReadableStream({
    start(controller) {
      nodeStream.on('data', (chunk) => controller.enqueue(chunk));
      nodeStream.on('end',  () => controller.close());
      nodeStream.on('error', (err) => controller.error(err));
    },
    cancel() { nodeStream.destroy(); },
  });

  return new NextResponse(webStream, {
    headers: {
      'Content-Type':        'application/zip',
      'Content-Disposition': `attachment; filename="${filename}"`,
      'Content-Length':      String(size),
    },
  });
}
