import { useEffect } from 'react';

import type ApiError from '~/lib/errors/ApiError';
import type { AppPage } from '~/src/components/NextApp/types';
import type { SelectedArtist } from '~/src/store/artists/types';
import type { Dispatch, State } from '~/src/store/types';
import type { NextPageContext } from 'next';

import { toDecodedItemPath } from '~/lib/router2/utils';
import { useAppLoading } from '~/src/components/NextApp/lib/CoreUi';
import PagePlaceholder from '~/src/components/PagePlaceholder';
import { useI18n, withI18n } from '~/src/lib/i18n';
import { reportError } from '~/src/lib/sentry';
import addServerTimingHeader from '~/src/lib/utils/addServerTimingHeader';
import { selectArtistStateItem } from '~/src/store/artists/selectors';
import { fetchItemByPathAction } from '~/src/store/paths/actions';
import {
  selectItemByPathGlobal,
  selectPathError,
  selectPathIsLoading,
  selectPathValue,
} from '~/src/store/paths/selectors';
import { useDispatch, useSelector } from '~/src/store/redux';
import ArtistPage from '~/src/views/ArtistPage';

interface ArtistPageProps {
  artistPath: string;
}

const fetchItem = ({
  dispatch,
  artistPath,
  silent,
}: {
  dispatch: Dispatch;
  artistPath: string;
  silent?: boolean;
}) => {
  return dispatch(
    fetchItemByPathAction({
      path: artistPath,
      silent,

      shouldRefetch: ({ state, existingItem }) => {
        const isNested = selectArtistStateItem(
          state,
          existingItem.id
        )?.isPartial;

        // When the artist in the store is from a 'nested' context
        // we force a refetch to ensure that we get the `artist.albums[]` too.
        // Without them we won't be able to render the releases section.
        return !!isNested;
      },
    })
  );
};

const ArtistNextPage: AppPage<ArtistPageProps> = ({ artistPath }) => {
  const { t } = useI18n('app');
  const dispatch = useDispatch();

  useEffect(() => {
    fetchItem({
      dispatch,
      artistPath,
      silent: true, // Do not throw errors on client side.
    });
  }, [artistPath, dispatch]);

  const pathIsLoading = useSelector((state: State) =>
    selectPathIsLoading(state, artistPath)
  );

  // show the app global loading bar while path is unresolved
  const setIsAppLoading = useAppLoading();

  useEffect(() => {
    setIsAppLoading(pathIsLoading);
  }, [pathIsLoading, setIsAppLoading]);

  const pathValue = useSelector((state: State) =>
    selectPathValue(state, artistPath)
  );

  const pathError = useSelector((state: State) =>
    selectPathError(state, artistPath)
  );

  const artistId = pathValue && pathValue.id;

  if (!pathValue) {
    return (
      <PagePlaceholder
        isLoading={pathIsLoading}
        error={pathError}
        toErrorText={({ status }) => {
          if (status === 404) {
            return t('errors.item');
          }
        }}
      />
    );
  }

  return <ArtistPage artistId={artistId!} />;
};

ArtistNextPage.getInitialProps = async (ctx): Promise<ArtistPageProps> => {
  const {
    res,
    query,
    reduxStore: { getState, dispatch },
    asPath,
    pathname,
  } = ctx;

  const artistPath = toDecodedItemPath(query);

  // if is server
  if (typeof window === 'undefined') {
    const timingStart = Date.now();

    const { serverRedirectIfNeeded } = await import(
      '~/src/lib/router2/redirectIfNeeded/serverRedirectIfNeeded'
    );

    if (res) {
      try {
        // SSR: block render until data fetched and report errors
        const result = await fetchItem({
          dispatch,
          artistPath,

          // Throw errors on server side to trigger try-catch below.
          silent: false,
        });

        if (result) {
          res.setHeader(
            'x-songwhip-resolve-path-from-api-cache',
            result.fromApiCache ? 'true' : 'false'
          );
        }
      } catch (error) {
        await onServerFetchError({
          error,
          ctx,
        });

        return {
          artistPath,
        };
      }

      const state = getState();

      const artist = selectItemByPathGlobal(
        state,
        artistPath
      ) as SelectedArtist;

      addServerTimingHeader(
        res,
        'songwhip-web-ssr-resolve-path',
        Date.now() - timingStart
      );

      serverRedirectIfNeeded({
        res,
        state,
        expectedPagePath: artist.pagePath,
        currentRoutePathname: pathname,
        currentAsPath: asPath!,
        pageOwnedByAccountIds: artist.ownedByAccountIds,
      });
    }
  }

  return {
    artistPath,
  };
};

const onServerFetchError = async ({
  error,
  ctx,
}: {
  error: ApiError;
  ctx: NextPageContext;
}) => {
  const { res } = ctx;

  // add the correct status-code, this is super important as returning
  // a non-error code means that the response will be cached upstream
  if (res) {
    res.statusCode = error.status || 500;
  }

  // don't report 404s, way too noisy
  if (error.status === 404) {
    return;
  }

  await reportError({
    error,
    nextCtx: ctx,
    extras: {
      caughtAt: 'pages/[param1]:onServerFetchError',
    },
  });
};

const ArtistNextPageWithI18n = withI18n(ArtistNextPage, ['item']);

export default ArtistNextPageWithI18n;
