let {
  BaseComponent,
  IColumn,
  buildColumns,
  SelectionMode,
  Toggle,
  ShimmeredDetailsList,
  IGroup,
  Fabric
} = window.Fabric;

const fileIcons: { name: string }[] = [
  { name: 'accdb' },
  { name: 'csv' },
  { name: 'docx' },
  { name: 'dotx' },
  { name: 'mpt' },
  { name: 'odt' },
  { name: 'one' },
  { name: 'onepkg' },
  { name: 'onetoc' },
  { name: 'pptx' },
  { name: 'pub' },
  { name: 'vsdx' },
  { name: 'xls' },
  { name: 'xlsx' },
  { name: 'xsn' }
];

const ITEMS_COUNT = 500;
const INTERVAL_DELAY = 2500;

let _items: IExampleItem[];

interface IShimmerApplicationExampleState {
  items?: IExampleItem[];
  columns?: IColumn[];
  isDataLoaded?: boolean;
}

class ShimmerApplicationExample extends BaseComponent<{}, IShimmerApplicationExampleState> {
  private _lastIntervalId: number;
  private _lastIndexWithData: number;

  constructor(props: {}) {
    super(props);

    this.state = {
      items: [],
      columns: _buildColumns(),
      isDataLoaded: false
    };
  }

  public render(): JSX.Element {
    const { items, columns, isDataLoaded } = this.state;

    return (
      <div>
        <Toggle
          label="Toggle to load content"
          style={{ display: 'block', marginBottom: '20px' }}
          checked={isDataLoaded}
          onChange={this._onLoadData}
          onText="Content"
          offText="Shimmer"
        />
        <div>
          <ShimmeredDetailsList
            setKey="items"
            items={items!}
            columns={columns}
            selectionMode={SelectionMode.none}
            onRenderItemColumn={this._onRenderItemColumn}
            enableShimmer={!isDataLoaded}
            listProps={{ renderedWindowsAhead: 0, renderedWindowsBehind: 0 }}
          />
        </div>
      </div>
    );
  }

  private _loadData = (): void => {
    this._lastIntervalId = this._async.setInterval(() => {
      const randomQuantity: number = Math.floor(Math.random() * 10) + 1;
      const itemsCopy = this.state.items!.slice(0);
      itemsCopy.splice(
        this._lastIndexWithData,
        randomQuantity,
        ..._items.slice(this._lastIndexWithData, this._lastIndexWithData + randomQuantity)
      );
      this._lastIndexWithData += randomQuantity;
      this.setState({
        items: itemsCopy
      });
    }, INTERVAL_DELAY);
  };

  private _onLoadData = (ev: React.MouseEvent<HTMLElement>, checked: boolean): void => {
    if (!_items) {
      _items = createListItems(ITEMS_COUNT);
      _items.map((item: IExampleItem) => {
        const randomFileType = this._randomFileIcon();
        item.thumbnail = randomFileType.url;
      });
    }

    let items: IExampleItem[];
    const randomQuantity: number = Math.floor(Math.random() * 10) + 1;
    if (checked) {
      items = _items.slice(0, randomQuantity).concat(new Array(ITEMS_COUNT - randomQuantity));
      this._lastIndexWithData = randomQuantity;
      this._loadData();
    } else {
      items = [];
      this._async.clearInterval(this._lastIntervalId);
    }
    this.setState({
      isDataLoaded: checked,
      items: items
    });
  };

  private _onRenderItemColumn = (item: IExampleItem, index: number, column: IColumn): JSX.Element | string | number => {
    if (column.key === 'thumbnail') {
      return <img src={item.thumbnail} />;
    }

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

  private _randomFileIcon(): { docType: string; url: string } {
    const docType: string = fileIcons[Math.floor(Math.random() * fileIcons.length) + 0].name;
    return {
      docType,
      url: `https://static2.sharepointonline.com/files/fabric/assets/brand-icons/document/svg/${docType}_16x1.svg`
    };
  }
}

function _buildColumns(): IColumn[] {
  const _item = createListItems(1);
  const columns: IColumn[] = buildColumns(_item);

  for (const column of columns) {
    if (column.key === 'thumbnail') {
      column.name = 'FileType';
      column.minWidth = 16;
      column.maxWidth = 16;
      column.isIconOnly = true;
      column.iconName = 'Page';
      break;
    }
  }

  return columns;
}

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(<ShimmerApplicationExample />, document.getElementById('content'));
