import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { createHash } from 'node:crypto';
import { getPublicBaseUrl } from '@/modules/sending/lib/public-base-url';
import { withAuth } from '@/core/auth';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

/**
 * Lädt ein Remote-Bild und speichert es lokal in `public/assets/upload/`.
 * Wird vom Briefing-Tab aufgerufen wenn der User aus den gescrapten Bildern eines auswählt
 * — wir wollen nicht die Original-URL als Hero referenzieren (kann später kaputt gehen),
 * sondern eine stabile lokal-gehostete Kopie.
 *
 * Sicherheit: gleiche SSRF-Guards wie scrape-url + nur image/* MIME + Größen-Limit 10 MB.
 */
const RequestSchema = z.object({
  url: z.string().url(),
});

const FETCH_TIMEOUT_MS = 10000;
const MAX_BYTES = 10 * 1024 * 1024;
const ALLOWED_MIME: Record<string, string> = {
  'image/png': '.png',
  'image/jpeg': '.jpg',
  'image/jpg': '.jpg',
  'image/webp': '.webp',
  'image/gif': '.gif',
  'image/svg+xml': '.svg',
};

const UPLOAD_DIR = join(process.cwd(), 'public', 'assets', 'upload');
const PUBLIC_PREFIX = '/assets/upload';
const USER_AGENT = 'Mozilla/5.0 (compatible; MailForgeBot/1.0; +https://mailforge.local)';

function isUrlSafe(rawUrl: string): boolean {
  try {
    const u = new URL(rawUrl);
    if (u.protocol !== 'http:' && u.protocol !== 'https:') return false;
    const host = u.hostname.toLowerCase();
    if (host === 'localhost' || host.endsWith('.localhost')) return false;
    if (host.startsWith('127.') || host === '::1' || host === '0.0.0.0') return false;
    if (host.startsWith('169.254.')) return false;
    if (host.startsWith('10.') || host.startsWith('192.168.')) return false;
    const m172 = host.match(/^172\.(\d+)\./);
    if (m172) {
      const second = parseInt(m172[1], 10);
      if (second >= 16 && second <= 31) return false;
    }
    return true;
  } catch {
    return false;
  }
}

export const POST = withAuth(async (req: NextRequest, _ctx) => {
  try {
    const body = await req.json();
    const parsed = RequestSchema.safeParse(body);
    if (!parsed.success) {
      return NextResponse.json({ error: 'Invalid input' }, { status: 400 });
    }
    const { url } = parsed.data;
    if (!isUrlSafe(url)) {
      return NextResponse.json({ error: 'URL gesperrt (private/loopback)' }, { status: 400 });
    }

    const controller = new AbortController();
    const timeoutHandle = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
    let buf: Buffer;
    let mime: string;
    try {
      const res = await fetch(url, {
        headers: { 'User-Agent': USER_AGENT },
        signal: controller.signal,
        redirect: 'follow',
      });
      if (!res.ok) {
        return NextResponse.json({ error: `Server antwortete mit ${res.status}` }, { status: 502 });
      }
      mime = (res.headers.get('content-type') ?? '').split(';')[0].trim().toLowerCase();
      const ext = ALLOWED_MIME[mime];
      if (!ext) {
        return NextResponse.json({
          error: `MIME nicht unterstützt: ${mime || 'unbekannt'}`,
        }, { status: 415 });
      }
      const contentLength = parseInt(res.headers.get('content-length') ?? '0', 10);
      if (contentLength > MAX_BYTES) {
        return NextResponse.json({ error: `Bild zu groß: ${(contentLength / 1024 / 1024).toFixed(1)} MB` }, { status: 413 });
      }
      const ab = await res.arrayBuffer();
      buf = Buffer.from(ab);
      if (buf.byteLength > MAX_BYTES) {
        return NextResponse.json({ error: `Bild zu groß: ${(buf.byteLength / 1024 / 1024).toFixed(1)} MB` }, { status: 413 });
      }
    } catch (e) {
      const isTimeout = e instanceof Error && e.name === 'AbortError';
      return NextResponse.json(
        { error: isTimeout ? `Download-Timeout nach ${FETCH_TIMEOUT_MS}ms` : (e instanceof Error ? e.message : 'Network error') },
        { status: isTimeout ? 504 : 502 },
      );
    } finally {
      clearTimeout(timeoutHandle);
    }

    if (!existsSync(UPLOAD_DIR)) mkdirSync(UPLOAD_DIR, { recursive: true });

    const ext = ALLOWED_MIME[mime];
    // Hash über Bytes — identisches Bild = identischer Pfad → idempotent + dedupe-fähig
    const hash = createHash('sha256').update(buf).digest('hex').slice(0, 24);
    const filename = `imported-${hash}${ext}`;
    const localPath = join(UPLOAD_DIR, filename);

    if (!existsSync(localPath)) {
      writeFileSync(localPath, buf);
    }

    const localUrl = `${PUBLIC_PREFIX}/${filename}`;
    const absoluteUrl = `${getPublicBaseUrl(req)}${localUrl}`;

    return NextResponse.json({
      ok: true,
      hero: {
        url: localUrl,
        absoluteUrl,
        bytes: buf.byteLength,
      },
    });
  } catch (err) {
    console.error('[/api/import-image-from-url] error:', err);
    return NextResponse.json(
      { error: err instanceof Error ? err.message : 'Internal error' },
      { status: 500 },
    );
  }
});
