"use client";

// Tell the framing page how tall this panel is.
//
// A cross-origin iframe cannot size itself to its content and the parent cannot
// measure across the origin boundary, so without this charon has to guess a
// height -- and a guess is either a panel that scrolls inside its own box or one
// with a band of dead space under it. This is the only way to get it right.
//
// PURELY ADDITIVE. A parent that ignores the message loses nothing but the
// exact fit, so the panel still works if charon never implements the listener.
// That is why the rest of the embed stays free of client JavaScript: this is the
// one thing that genuinely cannot be done on the server.
//
// The message is targeted at the configured ancestors rather than "*", so the
// height is not broadcast to any page that happens to frame us.

import { useEffect } from "react";

const MESSAGE_TYPE = "ampelos:profile:height";

export function FrameHeight({ targetOrigins }: { targetOrigins: string[] }) {
  useEffect(() => {
    if (window.parent === window) return;

    const post = (height: number) => {
      for (const origin of targetOrigins) {
        // A wrong origin here throws rather than leaking, which is the failure
        // direction we want; other targets still get theirs.
        try {
          window.parent.postMessage({ type: MESSAGE_TYPE, height }, origin);
        } catch {
          // The parent is not this origin. Nothing to do.
        }
      }
    };

    // ResizeObserver rather than a one-shot measure on mount: posters load late
    // and change the height after first paint, and a single measurement would
    // leave the frame sized for a panel with no images in it.
    const observer = new ResizeObserver((entries) => {
      const height = entries[0]?.target.scrollHeight ?? document.body.scrollHeight;
      if (height > 0) post(Math.ceil(height));
    });

    observer.observe(document.documentElement);
    post(Math.ceil(document.documentElement.scrollHeight));

    return () => observer.disconnect();
  }, [targetOrigins]);

  return null;
}
