let {
  HoverCard,
  IExpandingCardProps,
  DetailsList,
  buildColumns,
  IColumn,
  DirectionalHint,
  Fabric,
  KeyCodes,
  mergeStyleSets,
  IGroup,
  Fabric
} = window.Fabric;

const classNames = mergeStyleSets({
  compactCard: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    height: '100%'
  },
  expandedCard: {
    padding: '16px 24px'
  },
  item: {
    selectors: {
      '&:hover': {
        textDecoration: 'underline',
        cursor: 'pointer'
      }
    }
  }
});

interface IHoverCardFieldProps {
  content: string;
  expandingCardProps: IExpandingCardProps;
}

interface IHoverCardFieldState {
  contentRendered?: HTMLDivElement;
}

class HoverCardField extends React.Component<IHoverCardFieldProps, IHoverCardFieldState> {
  constructor(props: IHoverCardFieldProps) {
    super(props);

    this.state = {
      contentRendered: undefined
    };
  }

  public render() {
    return (
      <div
        ref={(c: HTMLDivElement) => !this.state.contentRendered && this.setState({ contentRendered: c })}
        data-is-focusable={true}
      >
        {this.props.content}
        {this.state.contentRendered && (
          <HoverCard
            expandingCardProps={this.props.expandingCardProps}
            target={this.state.contentRendered}
            cardDismissDelay={300}
            onCardVisible={this._log('onCardVisible')}
            onCardHide={this._log('onCardHide')}
            trapFocus={true}
            openHotKey={KeyCodes.enter}
          />
        )}
      </div>
    );
  }

  private _log(text: string): () => void {
    return (): void => {
      console.log(text);
    };
  }
}

class HoverCardTargetExample extends React.Component<{}, {}> {
  private _items: IExampleItem[] = createListItems(10);
  private _columns: IColumn[] = this._buildColumns();

  public render() {
    return (
      <Fabric>
        <p>
          Hover over the <i>key</i> cell of a row item to see the card or use the keyboard to navigate to it.
        </p>
        <p>
          When using the keyboard to tab to it, open the card with the hotKey and it will automatically focus the first
          focusable element in the card allowing further navigation inside the card.
        </p>
        <DetailsList
          setKey="hoverSet"
          items={this._items}
          columns={this._columns}
          onRenderItemColumn={this._onRenderItemColumn}
          ariaLabel="Hover card DetailsList test"
        />
      </Fabric>
    );
  }

  private _onRenderItemColumn = (item: IExampleItem, index: number, column: IColumn): JSX.Element | React.ReactText => {
    const expandingCardProps: IExpandingCardProps = {
      onRenderCompactCard: this._onRenderCompactCard,
      onRenderExpandedCard: this._onRenderExpandedCard,
      renderData: item,
      directionalHint: DirectionalHint.rightTopEdge,
      gapSpace: 16
    };

    if (column.key === 'key') {
      return (
        <div className={classNames.item}>
          <HoverCardField content={item.key} expandingCardProps={expandingCardProps} />
        </div>
      );
    }

    return item[column.key as keyof IExampleItem];
  };

  private _onRenderCompactCard = (item: IExampleItem): JSX.Element => {
    return (
      <div className={classNames.compactCard}>
        <a target="_blank" href={`http://wikipedia.org/wiki/${item.location}`}>
          {item.location}
        </a>
      </div>
    );
  };

  private _onRenderExpandedCard = (item: IExampleItem): JSX.Element => {
    return (
      <div className={classNames.expandedCard}>
        {item.description}
        <DetailsList setKey="expandedCardSet" items={this._items} columns={this._columns} />
      </div>
    );
  };

  private _buildColumns() {
    return buildColumns(this._items).filter(column => column.name === 'location' || column.name === 'key');
  }
}

const LOREM_IPSUM = (
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut ' +
  'labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut ' +
  'aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore ' +
  'eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt ' +
  'mollit anim id est laborum'
).split(' ');

const DATA = {
  color: ['red', 'blue', 'green', 'yellow'],
  shape: ['circle', 'square', 'triangle'],
  location: ['Seattle', 'New York', 'Chicago', 'Los Angeles', 'Portland']
};

interface IExampleItem {
  thumbnail: string;
  key: string;
  name: string;
  description: string;
  color: string;
  shape: string;
  location: string;
  width: number;
  height: number;
}

function createListItems(count: number, startIndex: number = 0): IExampleItem[] {
  return Array.apply(null, Array(count)).map((item: number, index: number) => {
    const size = 150 + Math.round(Math.random() * 100);

    return {
      thumbnail: `//placehold.it/${size}x${size}`,
      key: 'item-' + (index + startIndex) + ' ' + lorem(4),
      name: lorem(5),
      description: lorem(10 + Math.round(Math.random() * 50)),
      color: _randWord(DATA.color),
      shape: _randWord(DATA.shape),
      location: _randWord(DATA.location),
      width: size,
      height: size
    };
  });
}

function createGroups(
  groupCount: number,
  groupDepth: number,
  startIndex: number,
  itemsPerGroup: number,
  level: number = 0,
  key: string = '',
  isCollapsed?: boolean
): IGroup[] {
  if (key !== '') {
    key = key + '-';
  }
  const count = Math.pow(itemsPerGroup, groupDepth);
  return Array.apply(null, Array(groupCount)).map((value: number, index: number) => {
    return {
      count: count,
      key: 'group' + key + index,
      name: 'group ' + key + index,
      startIndex: index * count + startIndex,
      level: level,
      isCollapsed: isCollapsed,
      children:
        groupDepth > 1
          ? createGroups(groupCount, groupDepth - 1, index * count + startIndex, itemsPerGroup, level + 1, key + index)
          : []
    };
  });
}

function lorem(wordCount: number): string {
  return Array.apply(null, Array(wordCount))
    .map((item: number, idx: number) => {
      return LOREM_IPSUM[idx % LOREM_IPSUM.length];
    })
    .join(' ');
}

function isGroupable(key: string): boolean {
  return key === 'color' || key === 'shape' || key === 'location';
}

function _randWord(array: string[]): string {
  const index = Math.floor(Math.random() * array.length);
  return array[index];
}

ReactDOM.render(<HoverCardTargetExample />, document.getElementById('content'));
