import React, { useCallback, useMemo, useRef, useState } from 'react';
import { bem } from 'utils/bem';
import { ArtistRosterItem, ArtistRosterProject, ArtistTeam, Optional } from 'backend-api/models';
import { ResponsiveContainer } from 'common/components/sidebar-form/responsive-container';
import { LiveArtistCardStates, LoadableData, LoadingState } from 'common/types';
import { H4 } from 'common/components/typography';
import { GridItemLoader, LiveArtistCard, MoreArtistsCard, TitleLoader } from './components';
import { COLUMN_COUNT, GRID_CELL_SIZE, GRID_ITEM_GAP, LAST_ROW_COMPACT_LAYOUT, LIVE_ARTISTS_LIMIT } from './constants';
import { BEM_CLASS, SLiveArtist } from './s-live-artist';
import { ArtistRosterExpansionContainer } from 'projects/containers/artist-roster-expansion';
import { GetExpansionProjectsPayload } from 'projects/types';
import { useArtistRosterExpansion } from 'projects/hooks/use-artist-roster-expansion';
import { motion } from 'framer-motion';

interface LiveArtistProps {
  items: ArtistRosterItem[];
  loadingState: LoadingState;
  className?: string;
  artistTeamLoadable: LoadableData<ArtistTeam[]>;
  projectsLoadable: LoadableData<ArtistRosterProject[]>;
  getArtistTeams(id: string): void;
  getExpansionProjects(payload: GetExpansionProjectsPayload): void;
  expandedArtistId?: string;
  onItemExpand(id?: string): void;
}

const classes = bem(BEM_CLASS);

export const LiveArtist = React.memo(
  ({
    items,
    loadingState,
    className,
    artistTeamLoadable,
    projectsLoadable,
    getArtistTeams,
    getExpansionProjects,
    expandedArtistId,
    onItemExpand,
  }: LiveArtistProps) => {
    const [showAllArtists, setShowAllArtists] = useState(false);
    const getIndex = useCallback((artistId?: string) => items.findIndex(item => item.artist.id === artistId), [items]);
    const gridRef = useRef<HTMLDivElement>(null);

    const { expansionRow, arrowPosition, onItemClick, onCollapseFinish } = useArtistRosterExpansion({
      gridElement: gridRef.current,
      expandedArtistId,
      items,
      onItemExpand,
      gridGap: GRID_ITEM_GAP,
      columnCount: COLUMN_COUNT,
      isTriangleCenter: true,
      rowHeight: GRID_CELL_SIZE,
    });

    const getCardState = useCallback(
      (artist: ArtistRosterItem, selectedArtistId: Optional<string>): LiveArtistCardStates => {
        if (!selectedArtistId) {
          return LiveArtistCardStates.DEFAULT;
        }

        return artist.artist.id === selectedArtistId ? LiveArtistCardStates.SELECTED : LiveArtistCardStates.INACTIVE;
      },
      []
    );

    const gridItems = useMemo(() => {
      switch (loadingState) {
        case LoadingState.Started:
        case LoadingState.Idle: {
          return [<GridItemLoader key="1" />, <GridItemLoader key="2" />, <GridItemLoader key="3" />];
        }
        case LoadingState.Finished: {
          if (showAllArtists || items.length <= LIVE_ARTISTS_LIMIT) {
            return items.map(item => (
              <LiveArtistCard
                item={item}
                cardState={getCardState(item, expandedArtistId)}
                onSelectArtist={onItemClick}
                key={item.artist.id}
              />
            ));
          }

          const itemsToShow = items.slice(0, LIVE_ARTISTS_LIMIT - 1);
          const otherItems = items.slice(LIVE_ARTISTS_LIMIT - 1, items.length);

          const gridItems = itemsToShow.map((item: ArtistRosterItem) => (
            <LiveArtistCard
              item={item}
              cardState={getCardState(item, expandedArtistId)}
              onSelectArtist={onItemClick}
              key={item.artist.id}
            />
          ));

          gridItems.push(
            <MoreArtistsCard
              cardState={expandedArtistId === undefined ? LiveArtistCardStates.DEFAULT : LiveArtistCardStates.INACTIVE}
              artists={otherItems.map(item => item.artist)}
              onClick={() => {
                setShowAllArtists(true);
              }}
            />
          );

          return gridItems;
        }
        default: {
          return [];
        }
      }
    }, [loadingState, showAllArtists, items, expandedArtistId, getCardState, onItemClick]);

    const title = useMemo(() => {
      switch (loadingState) {
        case LoadingState.Idle:
        case LoadingState.Started: {
          return <TitleLoader />;
        }
        case LoadingState.Finished: {
          if (items.length > 0) {
            return <H4 className={classes('title')}>Live Artists ({items.length})</H4>;
          }
        }
        default: {
          return undefined;
        }
      }
    }, [items.length, loadingState]);

    const expandedArtist = useMemo(() => items[getIndex(expandedArtistId)]?.artist, [
      expandedArtistId,
      getIndex,
      items,
    ]);

    const isCompactLayout =
      (expandedArtistId !== undefined && expansionRow !== LAST_ROW_COMPACT_LAYOUT) ||
      items.length >= LIVE_ARTISTS_LIMIT - 1;

    return (
      <SLiveArtist
        className={className}
        expansionRow={expansionRow}
        isAnimate={isCompactLayout}
        itemsLength={items.length}
      >
        <ResponsiveContainer>
          <div className={classes('title-container')}>{title}</div>
        </ResponsiveContainer>
        <ResponsiveContainer>
          <motion.div ref={gridRef} className={classes('grid')}>
            {gridItems}
            {loadingState !== LoadingState.Started && (
              <ArtistRosterExpansionContainer
                className={classes('expanded-section')}
                isExpanded={expandedArtistId !== undefined && expansionRow > 1}
                artist={expandedArtist}
                artistTeamLoadable={artistTeamLoadable}
                projectsLoadable={projectsLoadable}
                getExpansionProjects={getExpansionProjects}
                getArtistTeams={getArtistTeams}
                arrowPosition={arrowPosition}
                onCollapseFinish={onCollapseFinish}
              />
            )}
          </motion.div>
        </ResponsiveContainer>
      </SLiveArtist>
    );
  }
);
