import type { APIRoute } from 'astro';
import { env } from 'cloudflare:workers';
import { sql } from 'drizzle-orm';
import { getDb, type DbEnv } from '../../../lib/db.js';
import { jsonError } from '../../../lib/http.js';
import { getSession, type SessionEnv } from '../../../lib/session.js';

export const prerender = false;

type DownloadEnv = SessionEnv & DbEnv & { MEDIA?: R2Bucket };

function normalizeRows(result: unknown): unknown[] {
  if (Array.isArray(result)) return result;
  const rows = (result as { rows?: unknown[] } | null)?.rows;
  return rows ?? [];
}

function sanitizeContentDispositionFilename(key: string): string {
  const basename = key.includes('/') ? key.slice(key.lastIndexOf('/') + 1) : key;
  return basename.replace(/"/g, "'").replace(/\\/g, '_').replace(/[\r\n]/g, '');
}

export const GET: APIRoute = async ({ params, request, cookies }) => {
  const cfEnv = env as DownloadEnv | undefined;
  if (!cfEnv?.SESSION) {
    return jsonError(503, 'service_unavailable', 'Session store not configured.');
  }
  if (!cfEnv?.DB && !cfEnv?.DATABASE_URL) {
    return jsonError(503, 'service_unavailable', 'Database is not configured.');
  }
  if (!cfEnv.MEDIA) {
    return jsonError(503, 'service_unavailable', 'Media storage is not configured.');
  }

  const session = await getSession(cfEnv, cookies);
  if (!session) {
    const next = encodeURIComponent(new URL(request.url).pathname);
    return Response.redirect(`/login?next=${next}`, 302);
  }

  const rawKey = params.key;
  if (!rawKey) {
    return jsonError(404, 'not_found', 'Download not found.');
  }

  let key: string;
  try {
    key = decodeURIComponent(rawKey);
  } catch {
    return jsonError(404, 'not_found', 'Download not found.');
  }

  const { db } = getDb(cfEnv);
  const grants = normalizeRows(
    await db.execute(sql`
      SELECT 1 FROM access_grant
      WHERE owner_key = ${'user:' + session.userId}
        AND blob_key = ${key}
      LIMIT 1
    `),
  );
  if (grants.length === 0) {
    return jsonError(404, 'not_found', 'Download not found.');
  }

  const obj = await cfEnv.MEDIA.get(key);
  if (!obj) {
    return jsonError(404, 'not_found', 'Download not found.');
  }

  const filename = sanitizeContentDispositionFilename(key);

  return new Response(obj.body, {
    status: 200,
    headers: {
      'Content-Type': obj.httpMetadata?.contentType ?? 'application/octet-stream',
      'Content-Disposition': `attachment; filename="${filename}"`,
      'Cache-Control': 'private, no-store',
    },
  });
};
