import type { APIRoute } from 'astro';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import sharp from 'sharp';

const PUBLIC_DIR = fileURLToPath(new URL('../../public/', import.meta.url));
const MAX_WIDTH = 2400;
const DEFAULT_QUALITY = 72;

function trimToList(value: string | undefined | null) {
  return String(value || '')
    .split(',')
    .map((item) => item.trim().toLowerCase())
    .filter(Boolean);
}

function parsePositiveInt(value: string | null, fallback: number) {
  const parsed = Number.parseInt(String(value || ''), 10);
  if (!Number.isFinite(parsed) || parsed <= 0) {
    return fallback;
  }

  return parsed;
}

function clampQuality(value: string | null) {
  return Math.min(Math.max(parsePositiveInt(value, DEFAULT_QUALITY), 40), 90);
}

function normalizeFormat(value: string | null) {
  switch (String(value || '').trim().toLowerCase()) {
    case 'avif':
      return 'avif' as const;
    case 'webp':
      return 'webp' as const;
    case 'png':
      return 'png' as const;
    default:
      return 'jpeg' as const;
  }
}

function contentTypeForFormat(format: 'avif' | 'webp' | 'jpeg' | 'png') {
  switch (format) {
    case 'avif':
      return 'image/avif';
    case 'webp':
      return 'image/webp';
    case 'png':
      return 'image/png';
    default:
      return 'image/jpeg';
  }
}

function isAllowedRemoteUrl(sourceUrl: URL, requestUrl: URL) {
  const allowedHosts = new Set([
    requestUrl.host.toLowerCase(),
    ...trimToList(import.meta.env.PUBLIC_IMAGE_ALLOWED_HOSTS as string | undefined),
    ...trimToList(process.env.PUBLIC_IMAGE_ALLOWED_HOSTS),
  ]);

  return (
    allowedHosts.has(sourceUrl.host.toLowerCase()) ||
    allowedHosts.has(sourceUrl.hostname.toLowerCase())
  );
}

async function readPublicAsset(sourceUrl: URL) {
  const decodedPath = decodeURIComponent(sourceUrl.pathname);
  const normalizedPath = path.normalize(decodedPath).replace(/^(\.\.[/\\])+/, '');
  const absolutePath = path.resolve(PUBLIC_DIR, `.${normalizedPath}`);

  if (!absolutePath.startsWith(PUBLIC_DIR) || !absolutePath.startsWith(path.resolve(PUBLIC_DIR))) {
    return null;
  }

  try {
    return await readFile(absolutePath);
  } catch {
    return null;
  }
}

async function loadSourceBuffer(sourceUrl: URL, requestUrl: URL) {
  if (sourceUrl.pathname === '/_img') {
    throw new Error('不允许递归优化图片请求');
  }

  if (sourceUrl.origin === requestUrl.origin) {
    const fromPublic = await readPublicAsset(sourceUrl);
    if (fromPublic) {
      return fromPublic;
    }
  } else if (!isAllowedRemoteUrl(sourceUrl, requestUrl)) {
    throw new Error('该图片域名未加入 PUBLIC_IMAGE_ALLOWED_HOSTS');
  }

  const response = await fetch(sourceUrl, {
    headers: {
      accept: 'image/*',
    },
  });

  if (!response.ok) {
    throw new Error(`图片源请求失败: ${response.status}`);
  }

  const bytes = Buffer.from(await response.arrayBuffer());
  if (!bytes.length) {
    throw new Error('图片源为空');
  }

  return bytes;
}

export const GET: APIRoute = async ({ url, request }) => {
  const src = url.searchParams.get('src')?.trim();

  if (!src || src.startsWith('data:') || src.startsWith('blob:')) {
    return new Response('invalid image src', { status: 400 });
  }

  let sourceUrl: URL;
  try {
    sourceUrl = new URL(src, request.url);
  } catch {
    return new Response('invalid image url', { status: 400 });
  }

  const requestUrl = new URL(request.url);
  const width = Math.min(parsePositiveInt(url.searchParams.get('w'), MAX_WIDTH), MAX_WIDTH);
  const quality = clampQuality(url.searchParams.get('q'));
  const format = normalizeFormat(url.searchParams.get('f'));

  try {
    const sourceBuffer = await loadSourceBuffer(sourceUrl, requestUrl);
    const image = sharp(sourceBuffer, {
      failOn: 'none',
      animated: false,
    });
    const metadata = await image.metadata();

    const resized = image.resize({
      width: metadata.width ? Math.min(width, metadata.width) : width,
      withoutEnlargement: true,
      fit: 'inside',
    });

    const output = await (format === 'avif'
      ? resized.avif({ quality }).toBuffer()
      : format === 'webp'
        ? resized.webp({ quality }).toBuffer()
        : format === 'png'
          ? resized.png({ quality }).toBuffer()
          : resized.jpeg({ quality, mozjpeg: true }).toBuffer());

    return new Response(new Uint8Array(output), {
      headers: {
        'Content-Type': contentTypeForFormat(format),
        'Cache-Control': 'public, max-age=604800, stale-while-revalidate=2592000',
        Vary: 'Accept',
      },
    });
  } catch (error) {
    return new Response(error instanceof Error ? error.message : 'image transform failed', {
      status: 400,
    });
  }
};
