import {
  FocusableItem,
  MenuDivider,
  MenuGroup,
  MenuHeader,
  MenuItem,
} from '@szhsin/react-menu';
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';

import Icon from '../components/icon';
import Menu2 from '../components/menu2';
import MenuConfirm from '../components/menu-confirm';
import { SHORTCUTS_LIMIT } from '../components/shortcuts-settings';
import Timeline from '../components/timeline';
import { api } from '../utils/api';
import { filteredItems } from '../utils/filters';
import showToast from '../utils/show-toast';
import states from '../utils/states';
import { saveStatus } from '../utils/states';
import { isMediaFirstInstance } from '../utils/store-utils';
import useTitle from '../utils/useTitle';

const LIMIT = 20;

// Limit is 4 per "mode"
// https://github.com/mastodon/mastodon/issues/15194
// Hard-coded https://github.com/mastodon/mastodon/blob/19614ba2477f3d12468f5ec251ce1cc5f8c6210c/app/models/tag_feed.rb#L4
const TAGS_LIMIT_PER_MODE = 4;
const TOTAL_TAGS_LIMIT = TAGS_LIMIT_PER_MODE + 1;

function Hashtags({ media: mediaView, columnMode, ...props }) {
  // const navigate = useNavigate();
  let { hashtag, ...params } = columnMode ? {} : useParams();
  if (props.hashtag) hashtag = props.hashtag;
  let hashtags = hashtag.trim().split(/[\s+]+/);
  hashtags.sort();
  hashtag = hashtags[0];
  const [searchParams, setSearchParams] = useSearchParams();
  const media = mediaView || !!searchParams.get('media');
  const linkParams = media ? '?media=1' : '';

  const { masto, instance, authenticated } = api({
    instance: props?.instance || params.instance,
  });
  const {
    masto: currentMasto,
    instance: currentInstance,
    authenticated: currentAuthenticated,
  } = api();
  const hashtagTitle = hashtags.map((t) => `#${t}`).join(' ');
  const hashtagPostTitle = media ? ` (Media only)` : '';
  const title = instance
    ? `${hashtagTitle}${hashtagPostTitle} on ${instance}`
    : `${hashtagTitle}${hashtagPostTitle}`;
  useTitle(title, `/:instance?/t/:hashtag`);
  const latestItem = useRef();

  const mediaFirst = useMemo(() => isMediaFirstInstance(), []);

  // const hashtagsIterator = useRef();
  const maxID = useRef(undefined);
  async function fetchHashtags(firstLoad) {
    // if (firstLoad || !hashtagsIterator.current) {
    //   hashtagsIterator.current = masto.v1.timelines.tag.$select(hashtag).list({
    //     limit: LIMIT,
    //     any: hashtags.slice(1),
    //   });
    // }
    // const results = await hashtagsIterator.current.next();

    // NOTE: Temporary fix for listHashtag not persisting `any` in subsequent calls.
    const results = await masto.v1.timelines.tag
      .$select(hashtag)
      .list({
        limit: LIMIT,
        any: hashtags.slice(1),
        maxId: firstLoad ? undefined : maxID.current,
        onlyMedia: media ? true : undefined,
      })
      .next();
    let { value } = results;
    if (value?.length) {
      if (firstLoad) {
        latestItem.current = value[0].id;
      }

      // value = filteredItems(value, 'public');
      value.forEach((item) => {
        saveStatus(item, instance, {
          skipThreading: media || mediaFirst, // If media view, no need to form threads
        });
      });

      maxID.current = value[value.length - 1].id;
    }
    return {
      ...results,
      value,
    };
  }

  async function checkForUpdates() {
    try {
      const results = await masto.v1.timelines.tag
        .$select(hashtag)
        .list({
          limit: 1,
          any: hashtags.slice(1),
          since_id: latestItem.current,
          onlyMedia: media,
        })
        .next();
      let { value } = results;
      const valueContainsLatestItem = value[0]?.id === latestItem.current; // since_id might not be supported
      if (value?.length && !valueContainsLatestItem) {
        value = filteredItems(value, 'public');
        return true;
      }
      return false;
    } catch (e) {
      return false;
    }
  }

  const [followUIState, setFollowUIState] = useState('default');
  const [info, setInfo] = useState();
  // Get hashtag info
  useEffect(() => {
    (async () => {
      try {
        const info = await masto.v1.tags.$select(hashtag).fetch();
        console.log(info);
        setInfo(info);
      } catch (e) {
        console.error(e);
      }
    })();
  }, [hashtag]);

  const reachLimit = hashtags.length >= TOTAL_TAGS_LIMIT;

  return (
    <Timeline
      key={instance + hashtagTitle}
      title={title}
      titleComponent={
        !!instance && (
          <h1 class="header-double-lines">
            <b>{hashtagTitle}</b>
            <div>{instance}</div>
          </h1>
        )
      }
      id="hashtag"
      instance={instance}
      emptyText="No one has posted anything with this tag yet."
      errorText="Unable to load posts with this tag"
      fetchItems={fetchHashtags}
      checkForUpdates={checkForUpdates}
      useItemID
      view={media || mediaFirst ? 'media' : undefined}
      refresh={media}
      // allowFilters
      filterContext="public"
      headerEnd={
        <Menu2
          portal
          setDownOverflow
          overflow="auto"
          // viewScroll="close"
          position="anchor"
          menuButton={
            <button type="button" class="plain">
              <Icon icon="more" size="l" />
            </button>
          }
        >
          {!!info && hashtags.length === 1 && (
            <>
              <MenuConfirm
                subMenu
                confirm={info.following}
                confirmLabel={`Unfollow #${hashtag}?`}
                disabled={followUIState === 'loading' || !authenticated}
                onClick={() => {
                  setFollowUIState('loading');
                  if (info.following) {
                    // const yes = confirm(`Unfollow #${hashtag}?`);
                    // if (!yes) {
                    //   setFollowUIState('default');
                    //   return;
                    // }
                    masto.v1.tags
                      .$select(hashtag)
                      .unfollow()
                      .then(() => {
                        setInfo({ ...info, following: false });
                        showToast(`Unfollowed #${hashtag}`);
                      })
                      .catch((e) => {
                        alert(e);
                        console.error(e);
                      })
                      .finally(() => {
                        setFollowUIState('default');
                      });
                  } else {
                    masto.v1.tags
                      .$select(hashtag)
                      .follow()
                      .then(() => {
                        setInfo({ ...info, following: true });
                        showToast(`Followed #${hashtag}`);
                      })
                      .catch((e) => {
                        alert(e);
                        console.error(e);
                      })
                      .finally(() => {
                        setFollowUIState('default');
                      });
                  }
                }}
              >
                {info.following ? (
                  <>
                    <Icon icon="check-circle" /> <span>Following…</span>
                  </>
                ) : (
                  <>
                    <Icon icon="plus" /> <span>Follow</span>
                  </>
                )}
              </MenuConfirm>
              <MenuDivider />
            </>
          )}
          {!mediaFirst && (
            <>
              <MenuHeader className="plain">Filters</MenuHeader>
              <MenuItem
                type="checkbox"
                checked={!!media}
                onClick={() => {
                  if (media) {
                    searchParams.delete('media');
                  } else {
                    searchParams.set('media', '1');
                  }
                  setSearchParams(searchParams);
                }}
              >
                <Icon icon="check-circle" />{' '}
                <span class="menu-grow">Media only</span>
              </MenuItem>
              <MenuDivider />
            </>
          )}
          <FocusableItem className="menu-field" disabled={reachLimit}>
            {({ ref }) => (
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  const newHashtag = e.target[0].value?.trim?.();
                  // Use includes but need to be case insensitive
                  if (
                    newHashtag &&
                    !hashtags.some(
                      (t) => t.toLowerCase() === newHashtag.toLowerCase(),
                    )
                  ) {
                    hashtags.push(newHashtag);
                    hashtags.sort();
                    // navigate(
                    //   instance
                    //     ? `/${instance}/t/${hashtags.join('+')}`
                    //     : `/t/${hashtags.join('+')}`,
                    // );
                    location.hash = instance
                      ? `/${instance}/t/${hashtags.join('+')}`
                      : `/t/${hashtags.join('+')}${linkParams}`;
                  }
                }}
              >
                <Icon icon="hashtag" />
                <input
                  ref={ref}
                  type="text"
                  placeholder={
                    reachLimit ? `Max ${TOTAL_TAGS_LIMIT} tags` : 'Add hashtag'
                  }
                  required
                  autocorrect="off"
                  autocapitalize="off"
                  spellCheck={false}
                  // no spaces, no hashtags
                  pattern="[^#][^\s#]+[^#]"
                  disabled={reachLimit}
                />
              </form>
            )}
          </FocusableItem>
          <MenuGroup takeOverflow>
            {hashtags.map((t, i) => (
              <MenuItem
                key={t}
                disabled={hashtags.length === 1}
                onClick={(e) => {
                  hashtags.splice(i, 1);
                  hashtags.sort();
                  // navigate(
                  //   instance
                  //     ? `/${instance}/t/${hashtags.join('+')}`
                  //     : `/t/${hashtags.join('+')}`,
                  // );
                  location.hash = instance
                    ? `/${instance}/t/${hashtags.join('+')}${linkParams}`
                    : `/t/${hashtags.join('+')}${linkParams}`;
                }}
              >
                <Icon icon="x" alt="Remove hashtag" class="danger-icon" />
                <span>
                  <span class="more-insignificant">#</span>
                  {t}
                </span>
              </MenuItem>
            ))}
          </MenuGroup>
          <MenuDivider />
          <MenuItem
            disabled={!currentAuthenticated}
            onClick={() => {
              if (states.shortcuts.length >= SHORTCUTS_LIMIT) {
                alert(
                  `Max ${SHORTCUTS_LIMIT} shortcuts reached. Unable to add shortcut.`,
                );
                return;
              }
              const shortcut = {
                type: 'hashtag',
                hashtag: hashtags.join(' '),
                instance,
                media: media ? 'on' : undefined,
              };
              // Check if already exists
              const exists = states.shortcuts.some(
                (s) =>
                  s.type === shortcut.type &&
                  s.hashtag
                    .split(/[\s+]+/)
                    .sort()
                    .join(' ') ===
                    shortcut.hashtag
                      .split(/[\s+]+/)
                      .sort()
                      .join(' ') &&
                  (s.instance ? s.instance === shortcut.instance : true) &&
                  (s.media ? !!s.media === !!shortcut.media : true),
              );
              if (exists) {
                alert('This shortcut already exists');
              } else {
                states.shortcuts.push(shortcut);
                showToast(`Hashtag shortcut added`);
              }
            }}
          >
            <Icon icon="shortcut" /> <span>Add to Shorcuts</span>
          </MenuItem>
          <MenuItem
            onClick={() => {
              let newInstance = prompt(
                'Enter a new instance e.g. "mastodon.social"',
              );
              if (!/\./.test(newInstance)) {
                if (newInstance) alert('Invalid instance');
                return;
              }
              if (newInstance) {
                newInstance = newInstance.toLowerCase().trim();
                // navigate(`/${newInstance}/t/${hashtags.join('+')}`);
                location.hash = `/${newInstance}/t/${hashtags.join(
                  '+',
                )}${linkParams}`;
              }
            }}
          >
            <Icon icon="bus" /> <span>Go to another instance…</span>
          </MenuItem>
          {currentInstance !== instance && (
            <MenuItem
              onClick={() => {
                location.hash = `/${currentInstance}/t/${hashtags.join(
                  '+',
                )}${linkParams}`;
              }}
            >
              <Icon icon="bus" />{' '}
              <small class="menu-double-lines">
                Go to my instance (<b>{currentInstance}</b>)
              </small>
            </MenuItem>
          )}
        </Menu2>
      }
    />
  );
}

export default Hashtags;
