import React, { useState, useEffect } from 'react';
import { useRouteMatch } from 'react-router';
import { Link as RouterLink } from 'react-router-dom';
import styled from 'styled-components';
import { ErrorBoundary } from 'react-error-boundary';
import InfiniteScroll from 'react-infinite-scroller';
import { FileText, ArrowLeft } from 'react-feather';

import {
  Heading2,
  Heading3,
  PageContent,
  PageWrapper,
  Body,
  BodySmall,
  LinkStyle,
} from '../../../shared/Styles';
import { RelatedArticle } from '../../../shared/Models';
import { API_BASE, RELATED_ENDPOINT, HOME_ROUTE } from '../../../shared/Constants';
import Loading from '../../common/Loading';
import RelatedResult from './RelatedResult';
import { parseAbstract } from '../../../shared/Util';
import Configuration, { ARTICLE_INFO } from '../../../Configuration';

const ArticleInfo = Configuration[ARTICLE_INFO];

const NotFoundComponent = () => <NotFound>Article not found</NotFound>;

const RelatedPage = () => {
  const {
    params: { articleId },
  } = useRouteMatch<any>();

  const [loading, setLoading] = useState<boolean>(false);
  const [notFound, setNotFound] = useState<boolean>(false);
  const [hasMore, setHasMore] = useState<boolean>(true);
  const [page, setPage] = useState<number>(1);
  const [queryId, setQueryId] = useState<string>('');

  const [originalArticle, setOriginalArticle] = useState<RelatedArticle | null>(null);
  const [relatedArticles, setRelatedArticles] = useState<RelatedArticle[] | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      if (articleId === undefined || articleId === null || articleId === '') {
        setLoading(false);
        setNotFound(true);
        setPage(1);
        return;
      }

      try {
        setLoading(true);
        setRelatedArticles(null);

        let response = await fetch(
          `${API_BASE}${RELATED_ENDPOINT}/${articleId.toLowerCase()}?page_number=${1}`,
        );
        setLoading(false);

        let data = await response.json();
        const { query_id, response: responseArticles } = data;
        const originalArticle = responseArticles
          ? responseArticles.find((a: RelatedArticle) => a.id === articleId)
          : null;

        setQueryId(query_id);
        setOriginalArticle(originalArticle);
        setRelatedArticles(responseArticles.filter((a: RelatedArticle) => a.id !== articleId));
        setPage(2);
      } catch {
        setLoading(false);
        setNotFound(true);
        setPage(2);
      }
    };

    fetchData();
  }, [articleId]);

  const loadMoreResults = async () => {
    let response = await fetch(
      `${API_BASE}${RELATED_ENDPOINT}/${articleId.toLowerCase()}?page_number=${page}`,
    );
    setPage(page + 1);

    if (response.status > 400) {
      setHasMore(false);
    }

    let data = await response.json();
    const { response: responseArticles } = data;
    const currentArticles = relatedArticles || [];
    setRelatedArticles([...currentArticles, ...responseArticles]);
  };

  const TitleRow = (
    <Row>
      <RelatedTitle>
        Related Articles <FileText size={24} style={{ marginLeft: '8px' }} />
      </RelatedTitle>
      <SearchLink to={HOME_ROUTE}>
        <ArrowLeft size={16} style={{ marginRight: '4px' }} />
        Search All Articles
      </SearchLink>
    </Row>
  );

  return (
    <PageWrapper>
      <PageContent>
        <ErrorBoundary FallbackComponent={NotFoundComponent}>
          <RelatedContent>
            {loading && <Loading />}
            {notFound && (
              <>
                {TitleRow}
                <NotFoundComponent />
              </>
            )}
            {originalArticle && relatedArticles && (
              <>
                {TitleRow}
                <OriginalArticle>
                  <SmallTitle>Showing articles related to:</SmallTitle>
                  <ArticleInfo article={originalArticle} boldTitle />
                  {originalArticle.abstract && (
                    <>
                      <AbstractTitle className="hideCollapsed">Abstract</AbstractTitle>
                      <Paragraph>{parseAbstract(originalArticle.abstract)}</Paragraph>
                    </>
                  )}
                </OriginalArticle>
                <InfiniteScroll
                  pageStart={page}
                  loadMore={loadMoreResults}
                  hasMore={hasMore}
                  loader={
                    <Row>
                      <Loading />
                    </Row>
                  }
                >
                  {relatedArticles.map((article, idx) => (
                    <RelatedResult
                      key={article.id}
                      article={article}
                      position={idx}
                      queryId={queryId}
                    />
                  ))}
                </InfiniteScroll>
                {relatedArticles.length === 0 && <NotFound>No related articles found</NotFound>}
              </>
            )}
          </RelatedContent>
        </ErrorBoundary>
      </PageContent>
    </PageWrapper>
  );
};

export default RelatedPage;

const RelatedContent = styled.div`
  width: 100%;
  margin-right: auto;
  display: flex;
  flex-direction: column;
`;

const RelatedTitle = styled.div`
  ${Heading2}
  font-weight: 700;
  font-size: 24px;
  display: flex;
  align-items: center;
`;

const NotFound = styled.div`
  ${Heading3}
  display: flex;
  margin-top: 32px;
  padding-bottom: 24px;
  color: ${({ theme }) => theme.darkGrey};
`;

const SmallTitle = styled.div`
  ${Body}
  padding-bottom: 16px;
  font-weight: 500;
  color: ${({ theme }) => theme.darkGrey};
`;

const Paragraph = styled.div`
  ${BodySmall}
  margin-bottom: 8px;
`;

const AbstractTitle = styled.div`
  ${BodySmall}
  font-weight: 700;
`;

const OriginalArticle = styled.div`
  margin-bottom: 16px;
  border: 1px solid ${({ theme }) => theme.yellow};
  border-bottom: 1px solid ${({ theme }) => theme.yellow};
  padding: 12px 12px 4px 12px;
  border-radius: 4px;
`;

const Row = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
  padding-bottom: 16px;
  border-bottom: 1px dotted ${({ theme }) => theme.lightGrey};
`;

const SearchLink = styled(RouterLink)`
  ${LinkStyle}
  display: flex;
  align-items: center;
`;