import * as React from "react";
import * as R from "ramda";
import { graphql, Link, navigate, PageProps } from "gatsby";
import { Helmet } from "react-helmet";
// import { Picker, Item } from "@adobe/react-spectrum";

import MasonryGallery from "../components/MasonryGallery";
import KeywordsPicker from "../components/KeywordsPicker";
import {
  compareDates,
  getGalleryPageUrl,
  getHelmetSafeBodyStyle,
  getVibrantStyle,
} from "../utils";
import Nav from "../components/Nav";
import { Item, Select } from "../components/Select";
import { Switch } from "../components/Switch";
import ColorPalette from "@spectrum-icons/workflow/ColorPalette";

const SORT_KEYS = {
  hue: ["fields", "imageMeta", "vibrantHue"],
  rating: ["fields", "imageMeta", "meta", "Rating"],
  // hue_debug: ["fields", "imageMeta", "dominantHue", 0],
  hue_debug: ["fields", "imageMeta", "dominantHue", "0"],
  date: ["fields", "imageMeta", "dateTaken"],
  datePublished: ["fields", "imageMeta", "datePublished"],
} as const;

export type GalleryImage =
  Queries.GalleryPageQueryQuery["all"]["nodes"][number];

function smartCompareDates(
  key: keyof typeof SORT_KEYS,
  left: GalleryImage,
  right: GalleryImage
) {
  let diff = compareDates(SORT_KEYS[key], left, right);
  if (diff !== 0) {
    return diff;
  }
  return compareDates(SORT_KEYS.date, left, right);
}

const GalleryPage = ({
  data,
  location,
}: PageProps<Queries.GalleryPageQueryQuery>) => {
  const hash = location.hash ? location.hash.replace("#", "") : "";

  const params = new URLSearchParams(location.search);
  const filterKeyword = params.get("filter");
  const sortKey = params.get("sort") ?? "rating";

  const showDebug = Boolean(params.get("debug")?.length);
  const [showPalette, setShowPalette] = React.useState(false);

  const onKeywordPick = React.useCallback((newKeyword: string | null) => {
    if (newKeyword) {
      try {
        window.plausible("Filter Keyword", {
          props: { keyword: newKeyword },
        });
      } catch (e) {
        // do nothing
      }
    }
  }, []);

  const setSortKey = React.useCallback(
    (newSortKey: string) => {
      try {
        window.plausible("Sort Gallery", {
          props: { key: newSortKey },
        });
      } catch (e) {
        // do nothing
      }
      navigate(
        getGalleryPageUrl(
          { sortKey: newSortKey, keyword: filterKeyword, showDebug },
          hash
        ),
        { replace: true }
      );
    },
    [filterKeyword, hash, showDebug]
  );

  const removeHash = React.useCallback(() => {
    if (!hash.length) {
      return;
    }
    // const url = new URL(
    //   typeof window !== "undefined"
    //     ? window.location.href.toString()
    //     : "https://chuckdries.com/photogallery/"
    // );

    // url.hash = "";
    // window.history.replaceState(null, "", url.href.toString());
    navigate(getGalleryPageUrl({ sortKey, keyword: filterKeyword, showDebug}, ""), { replace: true })
    window.removeEventListener("wheel", removeHash);
    window.removeEventListener("touchmove", removeHash);
  }, [hash, sortKey, filterKeyword, showDebug]);

  React.useEffect(() => {
    window.addEventListener("wheel", removeHash);
    window.addEventListener("touchmove", removeHash);
    return () => {
      window.removeEventListener("wheel", removeHash);
      window.removeEventListener("touchmove", removeHash);
    }
  }, [removeHash]);

  React.useEffect(() => {
    // hacky but it works for now
    requestAnimationFrame(() => {
      // don't scroll into view if user got here with back button or if we just cleared it
      if (!hash.length) {
        return;
      }
      const el = document.getElementById(hash);
      if (!el) {
        console.log("⚠️failed to find hash");
        return;
      }
      console.log("scrolling into view manually");
      el.scrollIntoView({
        block: hash.startsWith("all") ? "start" : "center",
      });
    });
  }, [hash]);

  const images: GalleryImage[] = React.useMemo(() => {
    const sort =
      sortKey === "date" || sortKey === "datePublished"
        ? R.sort((node1: typeof data["all"]["nodes"][number], node2) =>
            smartCompareDates(sortKey, node1, node2)
          )
        : R.sort(
            // @ts-ignore
            R.descend(R.path<GalleryImage>(SORT_KEYS[sortKey]))
          );

    const filter = filterKeyword
      ? R.filter((image) =>
          R.includes(
            filterKeyword,
            R.pathOr([], ["fields", "imageMeta", "meta", "Keywords"], image)
          )
        )
      : R.identity;

    try {
      const ret = R.pipe(
        // @ts-ignore
        sort,
        filter
      )(data.all.nodes) as any;
      return ret;
    } catch (e) {
      console.log("caught images!", e);
      return [];
    }
  }, [data, sortKey, filterKeyword]);

  const recents = React.useMemo(() => {
    return R.sort(
      (left, right) => smartCompareDates("datePublished", left, right),
      data.recents.nodes
    );
  }, [data]);

  const dataFn = React.useCallback(
    (image: GalleryImage): string | null => {
      if (!showDebug) {
        return null;
      }
      if (sortKey === "rating") {
        return `[${R.pathOr(null, SORT_KEYS.rating, image)}] ${image.base}`;
      }
      if (sortKey === "datePublished") {
        const date = R.pathOr(null, SORT_KEYS.datePublished, image);
        if (!date) {
          return null;
        }
        return new Date(date).toLocaleString();
      }
      return null;
    },
    [showDebug, sortKey]
  );

  return (
    <>
      {/* @ts-ignore */}
      <Helmet>
        <title>Photo Gallery | Chuck Dries</title>
        <body
          className="bg-white transition-color"
          // @ts-ignore
          style={getHelmetSafeBodyStyle(
            // @ts-ignore shrug
            getVibrantStyle({
              Muted: [0, 0, 0],
              LightMuted: [0, 0, 0],
              Vibrant: [0, 0, 0],
              LightVibrant: [0, 0, 0],
              DarkMuted: [238, 238, 238],
              DarkVibrant: [238, 238, 238],
            })
          )}
        />
      </Helmet>
      <div className="top-0 z-10">
        <div className="bg-vibrant-dark text-light-vibrant pb-1">
          <Nav
            className="mb-4"
            internalLinks={[
              { href: "/", label: "Home" },
              { href: "/photogallery/", label: "Gallery" },
            ]}
          />
        </div>
        <div className="gradient pb-6">
          <div className="px-4 md:px-8 flex items-baseline">
            <h3 className="mx-2 font-bold" id="recently">
              Recently published
            </h3>
            {sortKey !== "datePublished" && (
              <Link
                className="underline cursor-pointer text-gray-500"
                to="?sort=datePublished#all"
              >
                show more
              </Link>
            )}
          </div>
          <MasonryGallery
            aspectsByBreakpoint={{
              xs: 3,
              sm: 3,
              md: 4,
              lg: 4,
              xl: 5,
              "2xl": 6,
              "3xl": 8,
            }}
            images={recents}
            singleRow
          />
        </div>
        <div className="px-4 md:px-8 mt-2 pt-2">
          <h3 className="mx-2 font-bold" id="all">
            All images
          </h3>
        </div>
        <div className="flex flex-col lg:flex-row lg:items-end justify-between px-4 md:px-8 sm:mx-auto">
          <KeywordsPicker
            getHref={(val, selected) =>
              selected
                ? getGalleryPageUrl({ keyword: null, sortKey, showDebug }, hash)
                : getGalleryPageUrl({ keyword: val, sortKey, showDebug }, hash)
            }
            keywords={[
              "Boyce Thompson Arboretum",
              "winter",
              "night",
              "coast",
              // "city",
              "landscape",
              "flowers",
              "product",
              // "waterfall",
              // "fireworks",
              // "panoramic",
              "Portland Japanese Garden",
              // "shoot the light",
              // "sunset",
            ]}
            onPick={onKeywordPick}
            value={filterKeyword}
          />
          <div className="my-2 mr-2 flex flex-row items-end">
            <div className="border border-gray-400 rounded mr-2">
              <Switch
                isSelected={showPalette}
                onChange={(val) => setShowPalette(val)}
              >
                <ColorPalette
                  UNSAFE_style={{
                    width: "24px",
                    margin: "0 4px",
                  }}
                />
              </Switch>
            </div>
            <Select
              label="Sort by..."
              // @ts-ignore
              onSelectionChange={setSortKey}
              selectedKey={sortKey}
            >
              <Item key="rating">Curated</Item>
              <Item key="datePublished">Date published</Item>
              <Item key="date">Date taken</Item>
              <Item key="hue">Hue</Item>
            </Select>
          </div>
        </div>
      </div>
      <MasonryGallery
        aspectsByBreakpoint={{
          xs: 2,
          sm: 2,
          md: 3,
          lg: 4,
          xl: 5,
          "2xl": 6.1,
          "3xl": 8,
        }}
        dataFn={dataFn}
        debugHue={sortKey === "hue_debug"}
        images={images}
        linkState={{
          sortKey,
          filterKeyword,
        }}
        showPalette={showPalette}
      />
    </>
  );
};

export const query = graphql`
  query GalleryPageQuery {
    recents: allFile(
      filter: { sourceInstanceName: { eq: "gallery" } }
      sort: { fields: { imageMeta: { datePublished: DESC } } }
      limit: 10
    ) {
      ...GalleryImageFile
    }
    all: allFile(
      filter: { sourceInstanceName: { eq: "gallery" } }
      sort: { fields: { imageMeta: { dateTaken: DESC } } }
    ) {
      ...GalleryImageFile
    }
  }

  fragment GalleryImageFile on FileConnection {
    nodes {
      base
      childImageSharp {
        fluid {
          aspectRatio
        }
        gatsbyImageData(
          layout: CONSTRAINED
          height: 550
          placeholder: DOMINANT_COLOR
        )
      }
      fields {
        imageMeta {
          vibrantHue
          dominantHue
          dateTaken
          datePublished
          meta {
            Keywords
            Rating
            ObjectName
            CreateDate
            ModifyDate
          }
          vibrant {
            ...VibrantColors
          }
        }
      }
    }
  }
`;

export default GalleryPage;
