import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { RouteComponentProps, useLocation, useRouteMatch } from 'react-router-dom';
import { Tabs } from 'gdb-web-shared-components';
import { bem } from 'utils/bem';
import { useQuery } from 'hooks';
import { navigateTo, replaceTo } from 'utils/navigation';
import { ProjectRouting } from 'app/routing';
import { isProjectSummaryPath } from 'app/routing/guards';
import { paths } from 'app/routing/paths';
import { GlobalLayout } from 'app/components/global-layout';
import { dateFormatSelector } from 'common/selectors';
import { ErrorViewStates, ErrorView } from 'common-v2/components';
import { Loading } from 'common-v2/types';
import { useAppContext } from 'common-v2/hooks';
import { getProjectDetails, setErrorViewType, openShareModal, openEditArtistsModal } from 'project-v2/actions';
import { getActiveProjectTab, getProjectTabPath } from 'project-v2/transducers';
import { ProjectTab } from 'project-v2/types';
import { ShareModalContainer } from 'project-v2/containers';
import { errorViewTypeSelector, isEditingSelector, projectDetailsSelector } from 'project-v2/selectors';
import { Details, ProjectForm, DetailsLoading } from 'project-v2/components';
import { SProjectContainer, BEM_CLASS } from './s-project-container';
import { Head } from 'app/components/head';
import { getPageHeadTitle, getProjectName, makePermissionsChecker } from 'common-v2/transducers';
import { ACCESS_PERMISSIONS } from 'common-v2/constants';
import { ProjectFormContainer } from '../project-form-container';
import { ViewModeControls, EditModeControls } from './components';
import { permissionErrorModalOpenedSelector } from 'modals/permission-error-modal/selectors';
import { TabsLoader } from 'common/components/project-tabs/components';
import { Artist } from 'backend-api/models';
import { PermissionErrorModalContainer } from 'modals/permission-error-modal';
import FailedToLoadErrorImage from 'assets/error_failed_to_load.png';
import { UnclaimedProjectContainer } from './containers';
import { getProjectTabs } from './transducers';

interface MatchParams {
  id: string;
}

const classes = bem(BEM_CLASS);

export const ProjectContainer = React.memo(({ match }: RouteComponentProps<MatchParams>) => {
  const projectId = Number(match.params.id);

  const [isProjectFormVisible, setIsProjectFormVisible] = useState(false);

  const dispatch = useDispatch();
  const location = useLocation();
  const { query } = useQuery();
  const { url } = useRouteMatch();
  const { user: userInfo } = useAppContext();

  const isEditing = useSelector(isEditingSelector);
  const dateFormat = useSelector(dateFormatSelector);
  const projectDetails = useSelector(projectDetailsSelector);
  const errorViewType = useSelector(errorViewTypeSelector);
  const isEditingPermissionErrorModalOpened = useSelector(permissionErrorModalOpenedSelector);

  const headTitle = useMemo(() => getPageHeadTitle(getProjectName(projectDetails.data), errorViewType), [
    errorViewType,
    projectDetails.data,
  ]);
  const activeTab = useMemo(() => getActiveProjectTab(url, location.pathname), [location.pathname, url]);
  const canEditProject = useMemo(() => {
    if (projectDetails.loading !== Loading.Finished || !projectDetails.data.isClaimed) return false;
    return makePermissionsChecker(projectDetails.data)(ACCESS_PERMISSIONS.EDIT_PROJECT);
  }, [projectDetails.data, projectDetails.loading]);

  const openProjectEditForm = useCallback(() => setIsProjectFormVisible(true), []);
  const closeProjectEditForm = useCallback(() => setIsProjectFormVisible(false), []);
  const shareProjectHandler = useCallback(() => dispatch(openShareModal()), [dispatch]);
  const openArtistsEditingModal = useCallback(
    (artists: Artist[]) => {
      dispatch(openEditArtistsModal({ selectedArtists: artists }));
    },
    [dispatch]
  );
  const handleTabChange = useCallback(
    (value: ProjectTab) => {
      navigateTo(getProjectTabPath(projectId, value));
    },
    [projectId]
  );

  const shouldIgnoreUnsavedChanged = isEditingPermissionErrorModalOpened || !projectDetails.data?.isClaimed;

  const renderProjectDetails = () => {
    switch (projectDetails.loading) {
      case Loading.Idle:
      case Loading.Started:
        return <DetailsLoading />;
      case Loading.Finished:
        const editModeControls = <EditModeControls isLoading={isEditing} onCancel={closeProjectEditForm} />;
        const viewModeControls = projectDetails.data.isClaimed ? (
          <ViewModeControls
            canEditProject={canEditProject}
            onShareProject={shareProjectHandler}
            onEditProject={openProjectEditForm}
          />
        ) : null;

        return (
          <ProjectFormContainer project={projectDetails.data} onFinishEditing={closeProjectEditForm}>
            <Details
              dateFormat={dateFormat}
              data={projectDetails.data}
              isEditing={isProjectFormVisible}
              controls={isProjectFormVisible ? editModeControls : viewModeControls}
            >
              <ProjectForm
                project={projectDetails.data}
                isEditing={isEditing}
                shouldIgnoreUnsavedChanges={shouldIgnoreUnsavedChanged}
                dateFormat={dateFormat}
                onEditFeaturedArtists={openArtistsEditingModal}
              />
            </Details>

            <ShareModalContainer
              projectId={projectId}
              projectDetails={projectDetails.data}
              canEditProject={canEditProject}
            />
          </ProjectFormContainer>
        );
      case Loading.Failed:
        return null;
    }
  };

  const tabs = useMemo(() => {
    switch (projectDetails.loading) {
      case Loading.Idle:
      case Loading.Started:
        return <TabsLoader className={classes('tabs')} />;
      case Loading.Finished:
        return (
          <Tabs<ProjectTab>
            className={classes('tabs')}
            value={activeTab}
            tabsData={getProjectTabs(projectDetails.data.userRoles)}
            onChange={handleTabChange}
          />
        );
      case Loading.Failed:
        return null;
    }
  }, [activeTab, handleTabChange, projectDetails.loading, projectDetails.data?.userRoles]);

  const fetchProjectDetails = useCallback(() => {
    dispatch(getProjectDetails.request({ projectId, params: { fromSearch: query.fromSearch === 1 ? 1 : undefined } }));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dispatch, projectId]);

  const content = useMemo(() => {
    const handleClaimProject = () => {
      setIsProjectFormVisible(true);
    };

    if (projectDetails.loading === Loading.Failed) {
      return (
        <ErrorView
          config={{
            bottomImageSrc: FailedToLoadErrorImage,
            description: (
              <>
                Project data failed to load.
                <br />
                Please try refreshing the page.
              </>
            ),
            actionTitle: 'Refresh',
          }}
          action={fetchProjectDetails}
        />
      );
    }

    if (projectDetails.loading === Loading.Finished && !projectDetails.data.isClaimed) {
      return isProjectFormVisible ? null : (
        <main className={classes('content')}>
          <UnclaimedProjectContainer
            isAdmin={userInfo.isAdmin}
            projectDetails={projectDetails.data}
            onClaimProject={handleClaimProject}
            isClaimingInProgress={isProjectFormVisible}
          />
        </main>
      );
    }

    return (
      <>
        {tabs}

        <main className={classes('content')}>
          <ProjectRouting
            projectId={projectId}
            projectLoading={projectDetails.loading}
            projectDetails={projectDetails.data}
          />
        </main>
      </>
    );
  }, [projectId, tabs, isProjectFormVisible, fetchProjectDetails, projectDetails, userInfo.isAdmin]);

  useEffect(() => {
    if (isProjectSummaryPath(location.pathname + location.search)) {
      replaceTo(paths.mediaPlan(projectId), { query });
    }

    if (isNaN(projectId)) {
      dispatch(setErrorViewType(ErrorViewStates.notFound));
    } else {
      fetchProjectDetails();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dispatch, fetchProjectDetails]);

  return (
    <>
      <Head title={headTitle} />

      <SProjectContainer>
        <GlobalLayout className={classes('background')} errorConfig={{ type: errorViewType }}>
          <div className={classes('container')}>
            <header className={classes('header')}>{renderProjectDetails()}</header>

            {content}
          </div>
        </GlobalLayout>
      </SProjectContainer>

      <PermissionErrorModalContainer />
    </>
  );
});
