import path from 'path';
import { NextRequest, NextResponse } from 'next/server';
import { localStorage } from '@/lib/local-storage';
import { fetchPublicHttpUrl } from '@/lib/remote-fetch';

/**
 * Download proxy.
 *
 * Supports:
 * - remote http(s) URLs, fetched server-side to avoid browser CORS failures
 * - same-origin relative URLs
 * - local-storage URLs, read directly from disk with path traversal protection
 */
export async function GET(request: NextRequest) {
  const url = request.nextUrl.searchParams.get('url');
  const filename = sanitizeFilename(
    request.nextUrl.searchParams.get('filename') || 'download',
  );

  if (!url) {
    return NextResponse.json({ error: '缺少 url 参数' }, { status: 400 });
  }

  try {
    const localKey = getLocalStorageKey(url);
    if (localKey) {
      return downloadLocalStorageFile(localKey, filename);
    }

    const targetUrl = resolveDownloadUrl(url, request.nextUrl.origin);
    if (!targetUrl) {
      return NextResponse.json(
        { error: '仅支持 HTTP(S) URL 或站内文件 URL' },
        { status: 400 },
      );
    }

    const response = await fetchPublicHttpUrl(targetUrl, {
      signal: AbortSignal.timeout(60_000),
    });

    if (!response.ok) {
      return NextResponse.json(
        { error: `远程文件获取失败: ${response.status}` },
        { status: response.status },
      );
    }

    const contentType = response.headers.get('content-type') || 'application/octet-stream';
    const body = await response.arrayBuffer();

    return buildDownloadResponse(
      body,
      contentType,
      filename,
      body.byteLength,
    );
  } catch (err) {
    const msg = err instanceof Error ? err.message : '下载失败';
    console.error('[Download Proxy Error]', msg);
    return NextResponse.json({ error: `下载失败: ${msg}` }, { status: 502 });
  }
}

function getLocalStorageKey(url: string): string | null {
  let pathname = url;
  if (url.startsWith('http://') || url.startsWith('https://')) {
    try {
      pathname = new URL(url).pathname;
    } catch {
      return null;
    }
  }

  const prefix = '/api/local-storage/';
  if (!pathname.startsWith(prefix)) return null;

  try {
    const key = decodeURIComponent(pathname.slice(prefix.length));
    const normalized = path.posix.normalize(key).replace(/^\/+/, '');
    if (!normalized || normalized.startsWith('..') || normalized.includes('/../')) {
      return null;
    }
    return normalized;
  } catch {
    return null;
  }
}

function resolveDownloadUrl(url: string, origin: string): string | null {
  if (url.startsWith('http://') || url.startsWith('https://')) {
    return url;
  }

  if (url.startsWith('/') && !url.startsWith('//')) {
    return `${origin}${url}`;
  }

  return null;
}

function downloadLocalStorageFile(key: string, filename: string) {
  if (!localStorage.fileExists(key)) {
    return NextResponse.json({ error: '文件不存在' }, { status: 404 });
  }

  const fileBuffer = localStorage.readFile(key);
  const contentType = getContentType(key);

  return buildDownloadResponse(
    fileBuffer.buffer.slice(
      fileBuffer.byteOffset,
      fileBuffer.byteOffset + fileBuffer.byteLength,
    ) as ArrayBuffer,
    contentType,
    filename,
    fileBuffer.byteLength,
  );
}

function buildDownloadResponse(
  body: ArrayBuffer,
  contentType: string,
  filename: string,
  length: number,
) {
  return new NextResponse(body, {
    status: 200,
    headers: {
      'Content-Type': contentType,
      'Content-Disposition': `attachment; filename="${filename}"`,
      'Content-Length': String(length),
      'Cache-Control': 'no-cache',
    },
  });
}

function sanitizeFilename(filename: string): string {
  return path.basename(filename).replace(/[\r\n"]/g, '_') || 'download';
}

function getContentType(filePath: string): string {
  const extension = filePath.split('.').pop()?.toLowerCase();
  const contentTypeMap: Record<string, string> = {
    jpg: 'image/jpeg',
    jpeg: 'image/jpeg',
    png: 'image/png',
    webp: 'image/webp',
    gif: 'image/gif',
    mp4: 'video/mp4',
    avi: 'video/x-msvideo',
    mov: 'video/quicktime',
    wmv: 'video/x-ms-wmv',
    webm: 'video/webm',
  };

  return contentTypeMap[extension || ''] || 'application/octet-stream';
}
