---
import { Image } from "astro:assets";
import { getCollection } from "astro:content";
import type { ImageMetadata } from "astro";
import PhotoDetail from "@/components/PhotoDetail.astro";
import PhotosSubNav from "@/components/PhotosSubNav.astro";
import BaseLayout from "@/layouts/BaseLayout.astro";
import type { PhotoSidecar } from "@/lib/collections";
import {
  buildBreadcrumbs,
  buildCollectionPhotos,
  collectionSlug,
  getChildCollections,
} from "@/lib/collections";

type CollectionProps = {
  type: "collection";
  slug: string;
  title: string;
  description: string;
  location?: string;
  hasContent: boolean;
  childSlugs: string[];
  childTitles: Record<string, string>;
  childLocations: Record<string, string | undefined>;
  photoCount: number;
  breadcrumbs: { label: string; href: string }[];
};

type PhotoProps = {
  type: "photo";
  sidecar: PhotoSidecar;
  image: ImageMetadata;
  collectionSlug: string;
  collectionTitle: string;
  prevHref: string | null;
  nextHref: string | null;
  breadcrumbs: { label: string; href: string }[];
};

export async function getStaticPaths() {
  const allCollections = await getCollection(
    "collections_photos",
    ({ data }) => !data.draft,
  );

  const sidecars = import.meta.glob<PhotoSidecar>(
    "/src/content/photos/collections/**/*.json",
    { eager: true },
  );
  const imageModules = import.meta.glob<{ default: ImageMetadata }>(
    "/src/content/photos/collections/**/*.jpg",
    { eager: true },
  );

  const paths: {
    params: { slug: string | undefined };
    props: CollectionProps | PhotoProps;
  }[] = [];

  // Build a global flat photo list (sorted by collection slug) for cross-collection nav
  const sortedCollections = [...allCollections].sort((a, b) =>
    collectionSlug(a).localeCompare(collectionSlug(b)),
  );
  const globalPhotos: { cSlug: string; photoId: string }[] = [];
  const collectionPhotosMap = new Map<
    string,
    { sidecar: PhotoSidecar; image: ImageMetadata }[]
  >();
  for (const col of sortedCollections) {
    const slug = collectionSlug(col);
    const photos = buildCollectionPhotos(sidecars, imageModules, slug);
    collectionPhotosMap.set(slug, photos);
    for (const photo of photos) {
      globalPhotos.push({ cSlug: slug, photoId: photo.sidecar.id });
    }
  }

  for (const col of allCollections) {
    const slug = collectionSlug(col);
    const children = getChildCollections(slug, allCollections);
    const photos = collectionPhotosMap.get(slug) ?? [];
    const breadcrumbs = buildBreadcrumbs(slug, allCollections);

    // Collection index path
    paths.push({
      params: { slug: slug || undefined },
      props: {
        type: "collection",
        slug,
        title: col.data.title,
        description: col.data.description,
        ...(col.data.location !== undefined
          ? { location: col.data.location }
          : {}),
        hasContent: false, // render() called at page level
        childSlugs: children.map((c) => collectionSlug(c)),
        childTitles: Object.fromEntries(
          children.map((c) => [collectionSlug(c), c.data.title]),
        ),
        childLocations: Object.fromEntries(
          children.map((c) => [collectionSlug(c), c.data.location]),
        ),
        photoCount: photos.length,
        breadcrumbs,
      } satisfies CollectionProps,
    });

    // Photo detail paths — use global prev/next for cross-collection navigation
    photos.forEach((photo) => {
      const gi = globalPhotos.findIndex(
        (p) => p.cSlug === slug && p.photoId === photo.sidecar.id,
      );
      const prevG = globalPhotos[gi - 1];
      const nextG = globalPhotos[gi + 1];

      paths.push({
        params: { slug: `${slug}/${photo.sidecar.id}` },
        props: {
          type: "photo",
          sidecar: photo.sidecar,
          image: photo.image,
          collectionSlug: slug,
          collectionTitle: col.data.title,
          prevHref: prevG
            ? `/photos/collections/${prevG.cSlug}/${prevG.photoId}`
            : null,
          nextHref: nextG
            ? `/photos/collections/${nextG.cSlug}/${nextG.photoId}`
            : null,
          breadcrumbs: [
            ...breadcrumbs,
            {
              label: photo.sidecar.title[0] ?? photo.sidecar.id,
              href: `/photos/collections/${slug}/${photo.sidecar.id}`,
            },
          ],
        } satisfies PhotoProps,
      });
    });
  }

  return paths;
}

const props = Astro.props as CollectionProps | PhotoProps;

// For collection pages: load photos + child covers at render time
const sidecars = import.meta.glob<PhotoSidecar>(
  "/src/content/photos/collections/**/*.json",
  { eager: true },
);
const imageModules = import.meta.glob<{ default: ImageMetadata }>(
  "/src/content/photos/collections/**/*.jpg",
  { eager: true },
);

let photos: { sidecar: PhotoSidecar; image: ImageMetadata }[] = [];
let childCovers: Record<string, ImageMetadata | null> = {};

if (props.type === "collection") {
  photos = buildCollectionPhotos(sidecars, imageModules, props.slug);

  // Pick first image per child collection as cover
  for (const childSlug of props.childSlugs) {
    const prefix = `/src/content/photos/collections/${childSlug}/`;
    const cover = Object.entries(imageModules)
      .filter(([p]) => p.startsWith(prefix))
      .sort(([a], [b]) => a.localeCompare(b))[0];
    childCovers[childSlug] = cover?.[1]?.default ?? null;
  }
}

const BATCH_SIZE = 15;
---

{
  props.type === "photo" ? (
    <BaseLayout
      title={props.sidecar.title[0] ?? props.sidecar.id}
      description={props.sidecar.alt}
      image={{
        src: new URL(
          `/og/photos/${props.collectionSlug}/${props.sidecar.id}.png`,
          Astro.site,
        ).toString(),
        alt: props.sidecar.alt,
      }}
      navHidden={true}
      footerHidden={true}
    >
      <PhotoDetail
        sidecar={props.sidecar}
        image={props.image}
        prevHref={props.prevHref}
        nextHref={props.nextHref}
        backHref={`/photos/collections/${props.collectionSlug}`}
        backLabel={props.collectionTitle}
        canonicalUrl={new URL(
          `/photos/collections/${props.collectionSlug}/${props.sidecar.id}`,
          Astro.site,
        ).toString()}
      />
    </BaseLayout>
  ) : (
    <BaseLayout
      title={props.title}
      description={props.description}
      navDesktopHidden={true}
      footerDark={true}
      image={
        props.slug
          ? {
              src: new URL(
                `/og/photos/${props.slug}.png`,
                Astro.site,
              ).toString(),
              alt: props.title,
            }
          : undefined
      }
    >
      <div class="page">
        <main class="main">
          <PhotosSubNav />

          <nav class="breadcrumb" aria-label="Breadcrumb">
            {props.breadcrumbs.map((crumb, i) => (
              <>
                {i > 0 && <span aria-hidden="true">/</span>}
                {i < props.breadcrumbs.length - 1 ? (
                  <a href={crumb.href}>{crumb.label}</a>
                ) : (
                  <span aria-current="page">{crumb.label}</span>
                )}
              </>
            ))}
          </nav>

          <header class="collection-header">
            <h1 class="collection-title">{props.title}</h1>
            {props.location && (
              <p class="collection-location">{props.location}</p>
            )}
            {props.description && (
              <p class="collection-description">{props.description}</p>
            )}
          </header>

          {props.childSlugs.length > 0 && (
            <section class="sub-collections">
              <ul class="collection-grid" role="list">
                {props.childSlugs.map((childSlug) => {
                  const cover = childCovers[childSlug];
                  const title = props.childTitles[childSlug] ?? childSlug;
                  const location = props.childLocations[childSlug];
                  return (
                    <li class="collection-card">
                      <a
                        href={`/photos/collections/${childSlug}`}
                        class="collection-link"
                      >
                        {cover && (
                          <div class="collection-cover">
                            <Image
                              src={cover}
                              alt={title}
                              width={600}
                              height={400}
                              class="collection-img"
                            />
                          </div>
                        )}
                        <div class="collection-meta">
                          <span class="collection-name">{title}</span>
                          {location && (
                            <span class="collection-loc">{location}</span>
                          )}
                        </div>
                      </a>
                    </li>
                  );
                })}
              </ul>
            </section>
          )}

          {photos.length > 0 && (
            <>
              <div class="photo-grid h-feed" id="photo-grid">
                {photos.map((photo, i) => {
                  const ar = photo.image.width / photo.image.height;
                  return (
                    <div
                      class="photo-item h-entry"
                      data-ar={ar}
                      data-batch={Math.floor(i / BATCH_SIZE)}
                      data-hidden={i >= BATCH_SIZE ? "true" : undefined}
                    >
                      <a
                        href={`/photos/collections/${props.slug}/${photo.sidecar.id}`}
                        class="photo-link u-url"
                      >
                        <Image
                          src={photo.image}
                          alt={photo.sidecar.alt}
                          width={800}
                          height={Math.round(800 / ar)}
                          loading="lazy"
                          class="photo-img u-photo"
                        />
                      </a>
                      <time
                        class="dt-published"
                        datetime={new Date(photo.sidecar.date).toISOString()}
                        style="display:none"
                      >
                        {photo.sidecar.date}
                      </time>
                    </div>
                  );
                })}
              </div>
              <div id="sentinel" aria-hidden="true" />
              <div id="load-status" class="load-status" aria-live="polite" />
            </>
          )}
        </main>
      </div>
    </BaseLayout>
  )
}

<script>
  import justifiedLayout from "justified-layout";

  const grid = document.getElementById("photo-grid");
  if (grid) {
    const BATCH_SIZE = 15;
    const TARGET_ROW_HEIGHT = 280;
    const BOX_SPACING = 8;

    const allItems = Array.from(
      grid.querySelectorAll<HTMLElement>(".photo-item"),
    );
    const sentinel = document.getElementById("sentinel");
    const status = document.getElementById("load-status");

    let currentBatch = 0;
    const totalBatches =
      Math.ceil(
        allItems.filter((el) => el.hasAttribute("data-hidden")).length /
          BATCH_SIZE,
      ) + 1;

    function applyLayout() {
      if (window.innerWidth <= 640) {
        grid!.style.height = "";
        grid!.style.position = "";
        for (const item of allItems) {
          if (!item.hasAttribute("data-hidden")) item.style.cssText = "";
        }
        return;
      }

      const visibleItems = allItems.filter(
        (el) => !el.hasAttribute("data-hidden"),
      );
      const ratios = visibleItems.map((el) => Number(el.dataset.ar));

      const result = justifiedLayout(ratios, {
        containerWidth: grid!.offsetWidth,
        targetRowHeight: TARGET_ROW_HEIGHT,
        boxSpacing: BOX_SPACING,
        containerPadding: 0,
      });

      grid!.style.position = "relative";
      grid!.style.height = `${result.containerHeight}px`;

      for (let i = 0; i < visibleItems.length; i++) {
        const box = result.boxes[i];
        const item = visibleItems[i];
        if (!box || !item) continue;
        item.style.position = "absolute";
        item.style.top = `${box.top}px`;
        item.style.left = `${box.left}px`;
        item.style.width = `${box.width}px`;
        item.style.height = `${box.height}px`;
      }
    }

    function revealNextBatch() {
      currentBatch++;
      const toReveal = allItems.filter(
        (el) =>
          el.hasAttribute("data-hidden") &&
          Number(el.dataset.batch) === currentBatch,
      );
      if (toReveal.length === 0) {
        sentinel?.remove();
        return;
      }
      if (status) status.textContent = "Loading more photos…";
      for (const el of toReveal) {
        el.removeAttribute("data-hidden");
        el.classList.add("is-visible");
      }
      applyLayout();
      if (currentBatch >= totalBatches) sentinel?.remove();
      if (status) status.textContent = "";
    }

    let resizeTimer: ReturnType<typeof setTimeout>;
    window.addEventListener("resize", () => {
      clearTimeout(resizeTimer);
      resizeTimer = setTimeout(applyLayout, 150);
    });

    applyLayout();

    if (sentinel) {
      const observer = new IntersectionObserver(
        (entries) => {
          if (entries[0]?.isIntersecting) revealNextBatch();
        },
        { rootMargin: "400px" },
      );
      observer.observe(sentinel);
    }
  }
</script>

<style>
  .page {
    display: grid;
    grid-template-rows: auto 1fr auto;
    min-height: 100dvh;
    background: #111;
    color: #f5f5f3;
  }

  .page.dark {
    display: flex;
    flex-direction: column;
  }

  .main {
    max-width: var(--width-wide);
    margin: 0 auto;
    padding: 1.5rem;
    width: 100%;
  }

  /* Breadcrumb */
  .breadcrumb {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    color: #666;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
  }

  .breadcrumb a {
    color: #888;
    text-decoration: none;
  }

  .breadcrumb a:hover {
    color: #f5f5f3;
  }

  /* Collection header */
  .collection-header {
    margin-bottom: 1.5rem;
  }

  .collection-title {
    font-size: 1.5rem;
    font-weight: 500;
    margin-bottom: 0.25rem;
  }

  .collection-location {
    font-size: 0.85rem;
    color: #888;
    margin: 0;
  }

  .collection-description {
    margin-top: 0.5rem;
    font-size: 0.9rem;
    color: #aaa;
    line-height: 1.6;
    max-width: 60ch;
  }

  /* Sub-collections grid */
  .sub-collections {
    margin-bottom: 2rem;
  }

  .collection-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1rem;
    list-style: none;
    padding: 0;
    margin: 0;
  }

  .collection-card {
    border-radius: 2px;
    overflow: hidden;
  }

  .collection-link {
    display: block;
    text-decoration: none;
    color: inherit;
  }

  .collection-cover {
    aspect-ratio: 3 / 2;
    overflow: hidden;
  }

  .collection-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.4s ease;
  }

  .collection-link:hover .collection-img {
    transform: scale(1.03);
  }

  .collection-meta {
    padding: 0.6rem 0;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
  }

  .collection-name {
    font-size: 0.95rem;
    font-weight: 500;
  }

  .collection-loc {
    font-size: 0.8rem;
    color: #888;
  }

  /* Photo grid */
  .photo-grid {
    position: relative;
  }

  .photo-item {
    border-radius: 2px;
    overflow: hidden;
  }

  .photo-item[data-hidden] {
    display: none;
  }

  .photo-item.is-visible {
    animation: fadeIn 0.4s ease forwards;
  }

  @keyframes fadeIn {
    from {
      opacity: 0;
      transform: translateY(8px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  .photo-link {
    display: block;
    width: 100%;
    height: 100%;
    overflow: hidden;
  }

  .photo-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.4s ease;
  }

  .photo-link:hover .photo-img {
    transform: scale(1.03);
  }

  #sentinel {
    height: 1px;
    margin-top: 2rem;
  }

  .load-status {
    text-align: center;
    padding: 1rem;
    font-size: 0.85rem;
    color: #666;
    min-height: 2rem;
  }

  .page :global(.footer a) {
    color: #f5f5f3;
  }

  @media (max-width: 640px) {
    .main {
      padding: 0.25rem 0.75rem;
    }

    .collection-grid {
      grid-template-columns: repeat(2, 1fr);
      gap: 0.5rem;
    }

    .photo-grid {
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
      height: auto !important;
      position: static !important;
    }

    .photo-item {
      position: static !important;
      width: 100% !important;
      height: auto !important;
    }

    .photo-img {
      height: auto;
      object-fit: initial;
    }
  }
</style>
