import React, { useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
  approvalRequestsLoadingStateSelector,
  confirmDeleteMediaPlanModalSelector,
  isMediaPlanDropdownVisibleSelector,
  isMediaPlansProcessingSelector,
  mediaPlanSelector,
  mediaPlansSelector,
  projectMetricsSelector,
  approvalRequestsCampaignsSelector,
  mediaPlanModeSelector,
  approvalRequestsUsersSelector,
} from 'media-plan-v2/selectors';
import { LoadingState } from 'common/types';
import { Id, ProjectDetails } from 'backend-api/models';
import {
  closeDeleteMediaPlanConfirmationModal,
  closeMediaPlansDropdown,
  createMediaPlan,
  deleteMediaPlan,
  editMediaPlan,
  getAllMediaPlans,
  openDeleteMediaPlanConfirmationModal,
  openMediaPlansDropdown,
} from 'media-plan-v2/actions';
import { AnalyticsEvents, trackEvent } from 'utils/analytic';
import { useHeaderPermissions } from 'media-plan-v2/hooks';
import { useProjectCurrencyCode } from 'hooks';
import { BEM_CLASS, SMediaPlanHeaderContainer } from './s-media-plan-header-container';
import { bem } from 'utils/bem';
import {
  ConfirmationModal,
  MediaPlansDropdown,
  ReleaseInfo,
  TitleLoader,
  MediaPlanName,
} from 'media-plan-v2/components';
import { replaceTo } from 'common/utils/navigation';
import { paths } from 'app/routing/paths';
import { MediaPlanModeControls } from '../media-plan-mode-controls';
import { projectDetailsSelector } from 'project-v2/selectors';
import { ControlsContainer } from './containers';
import { THEME, useManageToasts } from 'gdb-web-shared-components';
import { ProjectSummaryMetrics, Requesters } from './components';
import { Loading } from 'common-v2/types';
import { isLoadingStateAllowUILoading } from 'media-plan-v2/transducers';
import { includesRole } from 'common/transducers';
import { ROLES } from 'common-v2/constants';
import { MediaPlanMode } from 'media-plan-v2/types';

interface Props {
  projectId: Id;
  mediaPlanId?: Id;
  projectLoading: Loading;
  projectDetails?: ProjectDetails;
  isFullScreen: boolean;
  onFullscreenClick(): void;
  onExportClick(): void;
}

const classes = bem(BEM_CLASS);

export const MediaPlanHeaderContainer = React.memo(
  ({
    projectId,
    mediaPlanId,
    projectLoading,
    projectDetails,
    isFullScreen,
    onFullscreenClick,
    onExportClick,
  }: Props) => {
    const dispatch = useDispatch();
    const { openToast } = useManageToasts(THEME.light);

    const { data: project } = useSelector(projectDetailsSelector);
    const mediaPlans = useSelector(mediaPlansSelector);
    const mediaPlan = useSelector(mediaPlanSelector);
    const mediaPlanMode = useSelector(mediaPlanModeSelector);
    const { loading: projectMetricsLoading, data: projectMetrics } = useSelector(projectMetricsSelector);
    const approvalRequestsLoading = useSelector(approvalRequestsLoadingStateSelector);
    const isMediaPlansProcessing = useSelector(isMediaPlansProcessingSelector);
    const isMediaPlansDropdownVisible = useSelector(isMediaPlanDropdownVisibleSelector);
    const confirmDeleteMediaPlanModal = useSelector(confirmDeleteMediaPlanModalSelector);
    const approvalRequestsCampaigns = useSelector(approvalRequestsCampaignsSelector);
    const approvalRequestsUsers = useSelector(approvalRequestsUsersSelector);

    const currencyCode = useProjectCurrencyCode();
    const { canEditMediaPlan, shouldShowMediaPlansDropdown } = useHeaderPermissions(project);

    const isMediaPlanListLoading =
      isLoadingStateAllowUILoading(projectLoading) || isLoadingStateAllowUILoading(mediaPlans.loading);
    const isMetricsLoading =
      isLoadingStateAllowUILoading(projectLoading) || isLoadingStateAllowUILoading(projectMetricsLoading);
    const isRequestersSectionShown = approvalRequestsUsers.length > 0 && mediaPlanMode === MediaPlanMode.APPROVAL;
    const isReleaseInfoSectionDisabled =
      mediaPlan.loading !== LoadingState.Finished || approvalRequestsLoading !== LoadingState.Finished;

    const onOpenMediaPlansDropdown = useCallback(() => dispatch(openMediaPlansDropdown()), [dispatch]);
    const onCloseMediaPlansDropdown = useCallback(() => dispatch(closeMediaPlansDropdown()), [dispatch]);

    const activeMediaPlanItem = useMemo(() => {
      if (!mediaPlanId) return;

      return mediaPlans.data.find(mediaPlan => mediaPlan.id === mediaPlanId);
    }, [mediaPlans, mediaPlanId]);

    const fetchMediaPlans = useCallback(() => {
      dispatch(getAllMediaPlans.request(projectId));
    }, [dispatch, projectId]);

    const onSelectMediaPlan = useCallback(
      (id: Id) => {
        replaceTo(paths.mediaPlan(projectId, id));
        onCloseMediaPlansDropdown();
      },
      [onCloseMediaPlansDropdown, projectId]
    );

    const onAddNewMediaPlan = useCallback(
      (name: string) => {
        dispatch(
          createMediaPlan.request({ projectId, payload: { name }, onMediaPlanCreated: onSelectMediaPlan, openToast })
        );

        trackEvent(AnalyticsEvents.MEDIA_PLAN_CREATED, { projectId, projectLabel: project?.label?.name });
      },
      [dispatch, onSelectMediaPlan, openToast, project?.label?.name, projectId]
    );

    const onEditMediaPlan = useCallback(
      (id: Id, name: string) => {
        dispatch(editMediaPlan.request({ projectId, mediaPlanId: id, payload: { name }, openToast }));
      },
      [dispatch, openToast, projectId]
    );

    const onMediaPlanDeleted = useCallback(
      (id: Id) => {
        if (mediaPlanId !== id) {
          return;
        }

        const mediaPlanToShow = mediaPlans.data.filter(mediaPlan => mediaPlan.id !== id)[0];

        if (!mediaPlanToShow) {
          return;
        }

        onSelectMediaPlan(mediaPlanToShow.id);
      },
      [mediaPlanId, mediaPlans.data, onSelectMediaPlan]
    );

    const showConfirmMediaPlanDeletionModal = useCallback(
      (id: Id) => dispatch(openDeleteMediaPlanConfirmationModal(id)),
      [dispatch]
    );

    const handleConfirmMediaPlanDeletionModalResult = useCallback(
      (shouldDeleteMediaPlan: boolean) => {
        if (!shouldDeleteMediaPlan) {
          dispatch(closeDeleteMediaPlanConfirmationModal());
          return;
        }

        if (!confirmDeleteMediaPlanModal.mediaPlanId) return;

        dispatch(
          deleteMediaPlan.request({
            projectId,
            mediaPlanId: confirmDeleteMediaPlanModal.mediaPlanId,
            onMediaPlanDeleted,
            openToast,
          })
        );
        dispatch(closeDeleteMediaPlanConfirmationModal());
        trackEvent(AnalyticsEvents.MEDIA_PLAN_DELETED, { projectId, projectLabel: project?.label?.name });
      },
      [
        confirmDeleteMediaPlanModal.mediaPlanId,
        dispatch,
        onMediaPlanDeleted,
        openToast,
        project?.label?.name,
        projectId,
      ]
    );

    const mediaPlanModeControls = useMemo(() => {
      const isUserHasApprovalPermission =
        !!projectDetails?.userRoles && includesRole(projectDetails.userRoles, ROLES.APPROVER);

      const isControlsAvailable =
        isUserHasApprovalPermission &&
        approvalRequestsCampaigns.length > 0 &&
        (mediaPlanMode === MediaPlanMode.APPROVAL || mediaPlanMode === MediaPlanMode.DEFAULT);

      return isControlsAvailable ? (
        <div className={classes('mode-controls')}>
          <MediaPlanModeControls projectId={projectId} mediaPlanId={mediaPlanId} />
        </div>
      ) : null;
    }, [projectDetails?.userRoles, approvalRequestsCampaigns.length, mediaPlanMode, projectId, mediaPlanId]);

    const titleWithLoader = isMediaPlanListLoading ? (
      <TitleLoader className={classes('title-loader')} />
    ) : shouldShowMediaPlansDropdown ? (
      <MediaPlansDropdown
        mediaPlans={mediaPlans.data}
        mediaPlansLoading={mediaPlans.loading}
        mediaPlanId={mediaPlanId}
        onCreateNew={onAddNewMediaPlan}
        onDelete={showConfirmMediaPlanDeletionModal}
        onItemClick={onSelectMediaPlan}
        onEdit={onEditMediaPlan}
        editable={canEditMediaPlan}
        loading={isMediaPlansProcessing}
        onOpen={onOpenMediaPlansDropdown}
        onClose={onCloseMediaPlansDropdown}
        isOpen={isMediaPlansDropdownVisible}
        mediaPlanName={activeMediaPlanItem?.name}
        refetch={fetchMediaPlans}
      />
    ) : (
      <MediaPlanName mediaPlanName={activeMediaPlanItem?.name} />
    );

    return (
      <SMediaPlanHeaderContainer>
        <div className={classes('title-container')}>
          {titleWithLoader}

          <ControlsContainer
            projectId={projectId}
            isFullScreen={isFullScreen}
            onFullscreenClick={onFullscreenClick}
            onExportClick={onExportClick}
          />
        </div>

        {mediaPlanModeControls}

        <div className={classes('header')}>
          <ProjectSummaryMetrics
            projectMetrics={projectMetrics}
            currencyCode={currencyCode}
            loading={isMetricsLoading}
            isFailedToLoad={projectMetricsLoading === LoadingState.Failed}
          />

          {mediaPlanId && (
            <ReleaseInfo
              projectId={projectId}
              mediaPlanId={mediaPlanId}
              loading={isMetricsLoading}
              disabled={isReleaseInfoSectionDisabled}
              isInputsDisabled={!canEditMediaPlan}
            />
          )}

          {isRequestersSectionShown && <Requesters className={classes('requesters')} users={approvalRequestsUsers} />}
        </div>

        <ConfirmationModal
          text="Deleting media plan cannot be undone."
          action={handleConfirmMediaPlanDeletionModalResult}
          isVisible={confirmDeleteMediaPlanModal.isVisible}
        />
      </SMediaPlanHeaderContainer>
    );
  }
);
