import * as React from 'react'
import { Popover, Tree, Icon, Button, Skeleton } from 'antd'
import { DataValue, compose } from 'react-apollo'
import { platforms, platforms_platforms } from '../graphql/types/platforms'
import { withPlatforms } from '../graphql'
import Search from 'antd/lib/input/Search'

export interface PlatformSelectValue {
  os?: string
  dist?: string
  codename?: string
}

export interface Props {
  value: PlatformSelectValue
  onChange: (value: PlatformSelectValue) => void
}

interface ChildData {
  platforms: DataValue<platforms, {}>
}

interface IState {
  showPopover: boolean
  searchTerm?: string
}

class PlatformSelect extends React.Component<Props & ChildData, IState> {
  state: IState = {
    showPopover: false,
  }

  render() {
    const { showPopover } = this.state

    return (
      <Popover
        placement="rightTop"
        title={'Select platform'}
        content={this.renderContent()}
        visible={showPopover}
      >
        <Button onClick={() => this.setState({ showPopover: !showPopover })}>
          <Icon type="filter" />
        </Button>
      </Popover>
    )
  }

  private renderContent = () => {
    const { searchTerm } = this.state
    const {
      platforms: { platforms = [] },
      value,
    } = this.props

    if (!platforms.length) {
      return <Skeleton active />
    }

    const filteredPlatforms = searchTerm
      ? this.getFilteredPlatform()
      : platforms

    const systems = Array.from(
      new Set(filteredPlatforms.map(platform => platform.os))
    )

    const systemIndex: { [k: string]: platforms_platforms[] } = systems.reduce(
      (index: any, system) => {
        index[system] = filteredPlatforms.filter(
          platform => platform.os === system
        )
        return index
      },
      {}
    )

    return (
      <div>
        <Search
          addonBefore={
            <Button
              size="small"
              onClick={() => this.unselect()}
              className="clean-btn"
              title="Unset selection"
            >
              <Icon type="stop" />
            </Button>
          }
          placeholder="Search"
          onChange={this.onChangeSearchTerm}
        />
        <Tree
          selectable
          defaultExpandAll
          onSelect={this.onSelect}
          selectedKeys={[JSON.stringify(value)]}
        >
          {systems.map(system => (
            <Tree.TreeNode title={system} key={system} selectable={false}>
              {systemIndex[system].map(platform => (
                <Tree.TreeNode
                  title={`${platform.dist}`}
                  key={`${system}-${platform.dist}`}
                  selectable={false}
                >
                  {platform.releases.map(release => (
                    <Tree.TreeNode
                      title={`${release.codename}`}
                      key={JSON.stringify({
                        os: system,
                        dist: platform.dist,
                        codename: release.codename,
                      })}
                    />
                  ))}
                </Tree.TreeNode>
              ))}
            </Tree.TreeNode>
          ))}
        </Tree>
      </div>
    )
  }

  private onChangeSearchTerm = (event: React.ChangeEvent<HTMLInputElement>) => {
    this.setState({ searchTerm: event.target.value })
  }

  private getFilteredPlatform() {
    const { searchTerm } = this.state
    const {
      platforms: { platforms = [] },
    } = this.props
    const LCSearchTerm = searchTerm.toLowerCase()

    return (
      platforms
        .map(platform => {
          const filteredReleases = platform.releases.filter(release => {
            const text = `${platform.os} ${platform.dist} ${
              release.codename
            }`.toLowerCase()
            return text.indexOf(LCSearchTerm) !== -1
          })

          if (filteredReleases.length) {
            return { ...platform, releases: filteredReleases }
          } else {
            return null // filter it out.
          }
        })
        // remove platforms without contained releases
        .filter(platform => platform !== null)
    )
  }

  private unselect = () => {
    this.props.onChange({})
  }

  private onSelect = (selectedKeys: string[]) => {
    const [key] = selectedKeys
    if (key === undefined) return
    const value = JSON.parse(key) as PlatformSelectValue
    this.props.onChange(value)
  }
}

export default compose(withPlatforms)(PlatformSelect)
