/**
 * Download images/videos from Facebook CDN with SHA256 deduplication.
 */

import { createHash } from "node:crypto";
import { mkdir, writeFile } from "node:fs/promises";
import { join, extname } from "node:path";
import { randomUUID } from "node:crypto";
import { query, now } from "../../db.js";

const MEDIA_DIR = "media";

interface DownloadOpts {
  url: string;
  type: "image" | "video";
  entityId?: string;
  contentId?: string;
  investigationId: string;
}

interface DownloadResult {
  mediaId: string;
  filePath: string;
  sha256: string;
}

export async function downloadMedia(
  opts: DownloadOpts,
): Promise<DownloadResult | null> {
  const { url, type, entityId, contentId, investigationId } = opts;

  try {
    // Fetch the resource
    const resp = await fetch(url, {
      headers: {
        "User-Agent":
          "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
      },
      redirect: "follow",
      signal: AbortSignal.timeout(60_000),
    });

    if (!resp.ok) {
      console.warn(
        `[downloadMedia] HTTP ${resp.status} for ${url.slice(0, 80)}…`,
      );
      return null;
    }

    const buf = Buffer.from(await resp.arrayBuffer());
    if (buf.length === 0) {
      console.warn("[downloadMedia] Empty response body");
      return null;
    }

    // SHA256 hash for dedup
    const sha256 = createHash("sha256").update(buf).digest("hex");

    // Check DB for existing media with same hash
    const existing = await query<{ id: string; file_path: string }>(
      `SELECT id, file_path FROM media WHERE sha256 = $1 AND investigation_id = $2 LIMIT 1`,
      [sha256, investigationId],
    );

    if (existing.rows.length > 0) {
      const row = existing.rows[0];
      return {
        mediaId: row.id,
        filePath: row.file_path,
        sha256,
      };
    }

    // Determine extension from content-type or URL
    const ext = inferExtension(resp.headers.get("content-type"), url, type);
    const shortHash = sha256.slice(0, 16);
    const fileName = `${type}_${shortHash}${ext}`;
    const filePath = join(MEDIA_DIR, fileName);

    // Ensure directory exists and save file
    await mkdir(MEDIA_DIR, { recursive: true });
    await writeFile(filePath, buf);

    // Extract image dimensions if applicable
    let width: number | undefined;
    let height: number | undefined;
    if (type === "image") {
      try {
        const sharp = (await import("sharp")).default;
        const meta = await sharp(buf).metadata();
        width = meta.width;
        height = meta.height;
      } catch {
        // sharp not available or invalid image — non-fatal
      }
    }

    // Insert into DB
    const mediaId = randomUUID();
    await query(
      `INSERT INTO media (id, investigation_id, entity_id, content_id, type, file_path, url_original, sha256, width, height, collected_at)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
       ON CONFLICT (id) DO NOTHING`,
      [
        mediaId,
        investigationId,
        entityId ?? null,
        contentId ?? null,
        type,
        filePath,
        url,
        sha256,
        width ?? null,
        height ?? null,
        now(),
      ],
    );

    return { mediaId, filePath, sha256 };
  } catch (err) {
    console.warn(
      `[downloadMedia] Failed for ${url.slice(0, 80)}: ${(err as Error).message}`,
    );
    return null;
  }
}

function inferExtension(
  contentType: string | null,
  url: string,
  type: "image" | "video",
): string {
  // Try content-type header
  if (contentType) {
    const mimeMap: Record<string, string> = {
      "image/jpeg": ".jpg",
      "image/png": ".png",
      "image/webp": ".webp",
      "image/gif": ".gif",
      "video/mp4": ".mp4",
      "video/webm": ".webm",
      "video/quicktime": ".mov",
    };
    const match = mimeMap[contentType.split(";")[0].trim().toLowerCase()];
    if (match) return match;
  }

  // Try URL extension
  try {
    const pathname = new URL(url).pathname;
    const ext = extname(pathname).toLowerCase();
    if (ext && ext.length <= 5) return ext;
  } catch {
    // malformed URL — fall through
  }

  // Defaults
  return type === "image" ? ".jpg" : ".mp4";
}
