import {
  createSignal,
  Show,
  onMount,
  type ParentComponent,
  children,
  Suspense,
} from "solid-js";
import { useDocumentTitle } from "../utils";
import { type mastodon } from "masto";
import Scaffold from "../material/Scaffold";
import {
  AppBar,
  ListItemSecondaryAction,
  ListItemText,
  MenuItem,
  Switch,
  Toolbar,
} from "@suid/material";
import { css } from "solid-styled";
import { TimeSourceProvider, createTimeSource } from "../platform/timesrc";
import ProfileMenuButton from "./ProfileMenuButton";
import Tabs from "../material/Tabs";
import Tab from "../material/Tab";
import { makeEventListener } from "@solid-primitives/event-listener";
import BottomSheet, {
  HERO as BOTTOM_SHEET_HERO,
} from "../material/BottomSheet";
import { $settings } from "../settings/stores";
import { useStore } from "@nanostores/solid";
import { HeroSourceProvider, type HeroSource } from "../platform/anim";
import { useNavigate } from "@solidjs/router";
import { useSignedInProfiles } from "../masto/acct";
import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
import TrendTimelinePanel from "./TrendTimelinePanel";
import TimelinePanel from "./TimelinePanel";

const Home: ParentComponent = (props) => {
  let panelList: HTMLDivElement;
  useDocumentTitle("Timelines");
  const now = createTimeSource();

  const settings$ = useStore($settings);

  const [profiles] = useSignedInProfiles();
  const profile = () => {
    const all = profiles();
    if (all.length > 0) {
      return all[0].inf;
    }
  };
  const client = () => {
    const all = profiles();
    return all?.[0]?.client;
  };
  const navigate = useNavigate();

  const [heroSrc, setHeroSrc] = createSignal<HeroSource>({});
  const [panelOffset, setPanelOffset] = createSignal(0);
  const prefetching = () => !settings$().prefetchTootsDisabled;
  const [currentFocusOn, setCurrentFocusOn] = createSignal<HTMLElement[]>([]);
  const [focusRange, setFocusRange] = createSignal([0, 0] as readonly [
    number,
    number,
  ]);

  const child = children(() => props.children);

  let scrollEventLockReleased = true;

  const recalculateTabIndicator = () => {
    scrollEventLockReleased = false;
    try {
      const { x: panelX, width: panelWidth } =
        panelList.getBoundingClientRect();
      let minIdx = +Infinity,
        maxIdx = -Infinity;
      const items = panelList.querySelectorAll(".tab-panel");
      const ranges = Array.from(items).map((x) => {
        const rect = x.getBoundingClientRect();
        const inlineStart = rect.x - panelX;
        const inlineEnd = rect.width + inlineStart;
        return [inlineStart, inlineEnd] as const;
      });
      for (let i = 0; i < items.length; i++) {
        const e = items.item(i);
        const [inlineStart, inlineEnd] = ranges[i];
        if (inlineStart >= 0 && inlineEnd <= panelWidth) {
          minIdx = Math.min(minIdx, i);
          maxIdx = Math.max(maxIdx, i);
          e.classList.add("active");
        } else {
          e.classList.remove("active");
        }
      }

      if (isFinite(minIdx) && isFinite(maxIdx)) {
        setFocusRange([minIdx, maxIdx]);
      }
    } finally {
      scrollEventLockReleased = true;
    }
  };

  onMount(() => {
    makeEventListener(panelList, "scroll", () => {
      if (scrollEventLockReleased) {
        requestAnimationFrame(recalculateTabIndicator);
      }
    });
    makeEventListener(window, "resize", () => {
      if (scrollEventLockReleased) {
        requestAnimationFrame(recalculateTabIndicator);
      }
    });
    requestAnimationFrame(recalculateTabIndicator);
  });

  const isTabFocus = (idx: number) => {
    const [start, end] = focusRange();
    if (!isFinite(start) || !isFinite(end)) return false;
    return idx >= start && idx <= end;
  };

  const onTabClick = (idx: number) => {
    const items = panelList.querySelectorAll(".tab-panel");
    if (items.length > idx) {
      items.item(idx).scrollIntoView({ block: "start", behavior: "smooth" });
    }
    if (isTabFocus(idx)) {
      items.item(idx).scrollTo({
        top: 0,
        behavior: "smooth",
      });
    }
  };

  const openFullScreenToot = (
    toot: mastodon.v1.Status,
    srcElement?: HTMLElement,
    reply?: boolean,
  ) => {
    const p = profiles()[0];
    const inf = p.account.inf ?? profile();
    if (!inf) {
      console.warn("no account info?");
      return;
    }
    setHeroSrc((x) =>
      Object.assign({}, x, { [BOTTOM_SHEET_HERO]: srcElement }),
    );
    const acct = `${inf.username}@${p.account.site}`;
    setTootBottomSheetCache(acct, toot);
    navigate(`/${encodeURIComponent(acct)}/${toot.id}`, {
      state: reply
        ? {
            tootReply: true,
          }
        : undefined,
    });
  };

  css`
    .tab-panel {
      overflow: visible auto;
      max-width: 560px;
      height: 100%;
      padding: 0 16px;
      scroll-snap-align: center;
      overscroll-behavior-block: none;

      @media (max-width: 600px) {
        padding: 0;
      }
    }

    .panel-list {
      display: grid;
      grid-auto-columns: 560px;
      grid-auto-flow: column;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      scroll-snap-stop: always;
      height: calc(100vh - var(--scaffold-topbar-height, 0px));
      height: calc(100dvh - var(--scaffold-topbar-height, 0px));
      padding-left: var(--safe-area-inset-left, 0);
      padding-right: var(--safe-area-inset-right, 0);

      @media (max-width: 600px) {
        grid-auto-columns: 100%;
      }
    }
  `;

  return (
    <>
      <Scaffold
        topbar={
          <AppBar position="static">
            <Toolbar
              variant="dense"
              class="responsive"
              sx={{ paddingTop: "var(--safe-area-inset-top, 0px)" }}
            >
              <Tabs onFocusChanged={setCurrentFocusOn} offset={panelOffset()}>
                <Tab focus={isTabFocus(0)} onClick={[onTabClick, 0]}>
                  Home
                </Tab>
                <Tab focus={isTabFocus(1)} onClick={[onTabClick, 1]}>
                  Trending
                </Tab>
                <Tab focus={isTabFocus(2)} onClick={[onTabClick, 2]}>
                  Public
                </Tab>
              </Tabs>
              <ProfileMenuButton profile={profile()}>
                <MenuItem
                  onClick={(e) =>
                    $settings.setKey(
                      "prefetchTootsDisabled",
                      !$settings.get().prefetchTootsDisabled,
                    )
                  }
                >
                  <ListItemText>Prefetch Toots</ListItemText>
                  <ListItemSecondaryAction>
                    <Switch checked={prefetching()}></Switch>
                  </ListItemSecondaryAction>
                </MenuItem>
              </ProfileMenuButton>
            </Toolbar>
          </AppBar>
        }
      >
        <TimeSourceProvider value={now}>
          <Show when={!!client()}>
            <div class="panel-list" ref={panelList!}>
              <div class="tab-panel">
                <div>
                  <TimelinePanel
                    client={client()}
                    name="home"
                    prefetch={prefetching()}
                    openFullScreenToot={openFullScreenToot}
                  />
                </div>
              </div>
              <div class="tab-panel">
                <div>
                  <TrendTimelinePanel
                    client={client()}
                    prefetch={prefetching()}
                    openFullScreenToot={openFullScreenToot}
                  />
                </div>
              </div>
              <div class="tab-panel">
                <div>
                  <TimelinePanel
                    client={client()}
                    name="public"
                    prefetch={prefetching()}
                    openFullScreenToot={openFullScreenToot}
                  />
                </div>
              </div>
              <div></div>
            </div>
          </Show>
        </TimeSourceProvider>
        <Suspense>
          <HeroSourceProvider value={[heroSrc, setHeroSrc]}>
            <BottomSheet open={!!child()}>{child()}</BottomSheet>
          </HeroSourceProvider>
        </Suspense>
      </Scaffold>
    </>
  );
};

export default Home;
