import * as React from "react"
import { InputSingleLine } from "./Input"
import styled from "styled-components"
import bp from "styled-components-breakpoint"
import Router from "next/router"
import withTranslate from "jamplay-common/i18n/withTranslate"
import { withState, lifecycle } from "recompose"
import getConfig from "jamplay-common/remote-config"
import { provider } from "jamplay-common/client"
import { getCategory } from "jamplay-common/enum/book-categories"
import { Icon } from ".."
import { compose, Query, QueryResult } from "react-apollo"

import Analytic, { getInstance } from "jamplay-common/client/analytic"
import { Link } from "jamplay-common/routing"

import { BookThumbnail } from "./Book"
import gql from "graphql-tag"

const SuggestionResultContainer = styled.div`
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  z-index: 9;
  display: none;

  .SuggestionResultDialog__wrapper {
    border-radius: 0 0 5px 5px;
    border: 1px solid ${(props) => props.theme.borderGrey};
    background-color: ${(props) => props.theme.matteWhite};
  }
  .SuggestionResultDialog__type-label {
    background-color: ${(props) => props.theme.pumpkin};
    color: ${(props) => props.theme.white};
    padding: 3px 5px;
    display: inline-block;
    border-radius: 5px;
  }

  .SuggestionResultDialog__see-all-wrapper {
    text-align: right;
    border-top: solid 1px ${(props) => props.theme.borderGrey};
    padding: 5px 13px 8px 5px;
    a {
      font-weight: bold;
      color: ${(props) => props.theme.matteBlack};
    }
  }
  .SuggestionResultDialog__no-content-wrapper {
    text-align: center;
    margin-top: 21px;
  }
  .SugestionResultDialog__loading-wrap {
    background: ${(props) => props.theme.matteWhite};
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    margin: 8px;
  }
  .SuggestionResultDialog__scroll {
    ${bp("mobile")`
      -webkit-overflow-scrolling: touch;
      overflow: auto;
    `} ${bp("tablet")`
      max-height: 999999px;
    `};
  }

  .AuthorContainer {
    .AuthorInfo__avatar-image {
      width: 40px;
      height: 40px;
      border: 1px solid ${(props) => props.theme.borderGrey};
    }
    .AuthorInfo__info-wrapper p {
      font-size: 1rem;
      font-weight: bold;
      color: ${(props) => props.theme.matteBlack};
    }
  }

  h6 {
    ${bp("mobile")`
      font-size: 16px;
    `} ${bp("tablet")`
      font-size: inherit;
    `};
  }

  transition: 0.222s ease-in-out all;
  transform: translate(0, 8px);
  opacity: 0;
  pointer-events: none;
  display: block;

  ${bp("mobile")`
    &.visible {
      opacity: 1;
      pointer-events: all;
      transform: translate(0, 0px);
    }
  `} ${bp("tablet")`
  `};
`

const BookSuggestionResultItemContainer = styled.div`
  cursor: pointer;
  a {
    text-decoration: none;
  }
  a label {
    cursor: pointer;
    color: #333;
  }
  ${bp("mobile")`
    padding: 5px 8px 5px 8px;
    .AuthorInfo {
    }
  `} ${bp("tablet")`
    .AuthorInfo {
      display: block;
    }
  `}

  &:hover {
    background-color: ${(props) => props.theme.white};
  }

  &:first-child {
  }
  &:last-child {
    border-bottom: none;
  }
  .BookSuggestionResultItem__cover {
    width: 35px;
  }
  .BookSuggestionResultItem__info-wrapper {
    width: 100%;
    display: flex;
    align-items: center;
  }

  .BookSuggestionResultItem__label {
    margin-left: 8px;
    font-weight: bold;
    word-break: break-all;
  }
  .BookSuggestionResultItem__label--highlight {
    background-color: ${(props) => props.theme.gold};
  }
  .AuthorInfo {
    clear: both;
  }
  .AuthorInfo__avatar-image {
    width: 35px;
    height: 35px;

    ${bp("mobile")`
      display: none;
    `} ${bp("tablet")`
      display: block;
    `};
  }

  .BookSuggestionResultItem__cover-wrapper {
    width: 35px;
    margin-right: 8px;
    ${bp("mobile")`
      display: none;
    `} ${bp("tablet")`
      display: block;
    `};

    &.author {
      border: none;

      .thumbnail {
        width: 35px;
        height: 35px;
        border-radius: 50%;
      }
      .thumbnail:before {
        padding-top: 0;
      }
      .thumbnail:after {
        border: none;
      }
    }
  }

  .BookSuggestionResultItem__tags-container {
    font-size: 0.6em;

    ${bp("mobile")`
      display: none;
    `} ${bp("tablet")`
      display: block;
    `};
  }
  .BookSuggestionResultItem__tag {
    border: 1px solid ${(props) => props.theme.borderGrey};
    color: ${(props) => props.theme.darkGrey};
    padding: 0px 5px;
    margin: 2px 1px;
    border-radius: 8px;
    float: left;
    &:first-child {
      margin-left: 0;
    }
    &:last-child {
      margin-right: 0;
    }
  }
`

function navigateToResultPage(value: string, type: string = "book") {
  Link.Search.go(Router, {
    category: "ALL",
    v: value,
    sort: "SCORE",
    type
  })
}

function preventDefault(e) {
  e.preventDefault()
}
export const BookSuggestionResultItem = (
  props: {
    _id: string
    thumbnailImage?: string
    category?: string
    onClearSearchText?: () => void
  } & {
    title?: string
    highlightText: string
    __typename: "Author" | "Book"
  } & withTranslatePropType
) => {
  let url = `/search?v=${props.title}&category=ALL&sort=SCORE`
  let type = "book"
  if (props.__typename === "Author") {
    url = `${url}&type=author`
    type = "author"
  }
  function SendEventAndNavigate(sendEvent) {
    return (e) => {
      e.preventDefault()
      sendEvent("search_input", "click-suggestion", `${props.title}`, 0)
      navigateToResultPage(props.title || "", type)
    }
  }
  function categoryLowerCase(cat) {
    if (!cat) {
      return "all"
    }
    return getCategory(cat).prefix
  }
  function dismissSearchSuggestion() {
    if (props.onClearSearchText) {
      props.onClearSearchText()
    }
    const activeElement: any = document.activeElement
    activeElement.blur()
  }
  const Routing = type === "book" ? Link.BookDetail : Link.Author
  const paramsCustom =
    type === "book"
      ? { _id: props._id, category: categoryLowerCase(props.category) }
      : { id: props._id }
  return (
    <Analytic>
      {({ sendEvent }) => (
        <BookSuggestionResultItemContainer>
          <Routing
            params={paramsCustom as any}
            onClick={dismissSearchSuggestion}
          >
            <a
              style={{ display: "block" }}
              onClick={SendEventAndNavigate(sendEvent)}
              onMouseDown={preventDefault}
            >
              <div className={"BookSuggestionResultItem__info-wrapper"}>
                <div
                  className={`BookSuggestionResultItem__cover-wrapper ${type}`}
                >
                  <BookThumbnail
                    book={{
                      _id: props._id,
                      thumbnailImage: props.thumbnailImage,
                      categories: [props.category || "ROMANTIC"]
                    }}
                  />
                </div>
                <label
                  className={"BookSuggestionResultItem__label"}
                  dangerouslySetInnerHTML={{
                    __html: props.title || ""
                  }}
                />
              </div>
            </a>
          </Routing>
        </BookSuggestionResultItemContainer>
      )}
    </Analytic>
  )
}

export const SEARCH_SUGGESTION_QUERY = gql`
  query($value: String!) {
    books: searchBook(value: $value, limit: 5) {
      pageInfo {
        total
      }
      data {
        _id
        title
        thumbnailImage
        categories
        tags
      }
    }
    authors: searchAuthor(value: $value, limit: 3) {
      pageInfo {
        total
      }
      data {
        name
        _id
        profilePicture
      }
    }
  }
`

type SearchSuggestionTData = {
  autoSuggestion: {
    books: BookItemData[]
    authors: AuthorItemData[]
  }
}
type SearchSuggestionQueryPropTypes = {
  variables: { value: string }
  children: (
    results: SearchSuggestionTData["autoSuggestion"],
    loading
  ) => JSX.Element | JSX.Element[]
}
const SearchSuggestionQuery: React.SFC<SearchSuggestionQueryPropTypes> = ({
  children,
  variables
}) => {
  return (
    <Query
      query={SEARCH_SUGGESTION_QUERY}
      variables={variables}
      context={{ service: "core" }}
      ssr={false}
    >
      {({
        data,
        loading
      }: QueryResult<{ books: any; authors: any }, { value: string }>) => {
        if (data) {
          if (data.books && data.authors) {
            return children(
              {
                books: data.books.data,
                authors: data.authors.data
              },
              loading
            )
          } else {
            return children({ books: [], authors: [] }, loading)
          }
        } else {
          return children({ books: [], authors: [] }, loading)
        }
      }}
    </Query>
  )
}

export interface SuggestionResultDialogPropTypes extends withTranslatePropType {
  visible: boolean
  value: string
  onClearSearchText?: () => void
}
interface ISuggestionResultContainer
  extends React.SFC<SuggestionResultDialogPropTypes> {
  fragments: {
    author: any
    book: any
  }
}
export const SuggestionResultDialog: ISuggestionResultContainer = Object.assign(
  (props: SuggestionResultDialogPropTypes & withTranslatePropType) => {
    if (!props.t) {
      return (
        <div
          className="no-translate-provider"
          data-name="hidden, no i18n provider to this component"
        />
      )
    }

    return (
      <SuggestionResultContainer className={props.visible ? "visible" : ""}>
        <div className="SuggestionResultDialog__wrapper">
          <div className="SuggestionResultDialog__scroll">
            <SearchSuggestionQuery variables={{ value: props.value }}>
              {(results) => {
                const BookItemResult = results.books.map((book) => (
                  <BookSuggestionResultItem
                    highlightText={props.value}
                    _id={book._id}
                    key={book._id}
                    __typename={"Book"}
                    title={book.title}
                    category={book.categories[0]}
                    thumbnailImage={book.thumbnailImage}
                    onClearSearchText={props.onClearSearchText}
                  />
                ))

                const AuthorItemResult = results.authors.map((author) => (
                  <BookSuggestionResultItem
                    highlightText={props.value}
                    _id={author._id}
                    key={author._id}
                    __typename={"Author"}
                    title={author.name}
                    thumbnailImage={author.profilePicture}
                    onClearSearchText={props.onClearSearchText}
                  />
                ))

                return [...BookItemResult, ...AuthorItemResult]
              }}
            </SearchSuggestionQuery>
            <SearchSuggestionQuery variables={{ value: props.value }}>
              {(results) =>
                [...results.authors, ...results.books].length <= 0 ? (
                  <div className="SuggestionResultDialog__no-content-wrapper">
                    <img
                      width={200}
                      src={`${getConfig().publicRuntimeConfig.staticFolder ||
                        ""}/ui-assets/images/no-content@2x.png`}
                    />
                    <p
                      dangerouslySetInnerHTML={{
                        __html: (props.t && props.t("search/no-content")) || ""
                      }}
                    />
                  </div>
                ) : (
                  <div />
                )
              }
            </SearchSuggestionQuery>
          </div>
          <div className="SuggestionResultDialog__see-all-wrapper">
            <a
              onMouseDown={preventDefault}
              href={`/search?v=${props.value}&category=ALL&sort=SCORE`}
            >
              {props.t("search/see-all-result", { value: props.value })}
            </a>
          </div>
        </div>
      </SuggestionResultContainer>
    )
  }
)

export interface SearchTextInputPropTypes
  extends withTranslatePropType,
    React.InputHTMLAttributes<any> {
  value: string
  isLoading: { [key: string]: boolean }
  forceFocus?: boolean
  onChange: (s: any) => void
}
const SearchTextInputContainer = styled.div.attrs({
  className: "SearchTextInput"
})`
  display: block;
  position: relative;
  .SearchTextInputContainer__input-wrap {
    display: flex;
    .jamplay-icon {
      padding: 8px 18px 8px 18px;
      color: white;
      font-size: 21px;
    }
  }
  .SeachTextInputContainer__input-wrap__input--result-active {
    border-radius: 5px 0px 0 0 !important;
  }
  .SeachTextInputContainer__search-button--result-active {
    border-radius: 0px 5px 0 0 !important;
  }
`
export class SearchTextInput extends React.Component<
  SearchTextInputPropTypes,
  { isFocus: boolean }
> {
  public static defaultProps = {}
  constructor(props) {
    super(props)
    this.state = {
      isFocus: props.initFocus || false
    }
  }
  public onInputFocus = (value: boolean) => {
    return (e) => {
      this.setState({
        isFocus: value
      })
    }
  }
  public pushResult = () => {
    Link.Search.go(Router, {
      category: "ALL",
      v: this.props.value,
      sort: "SCORE"
    })
  }
  public onKeyPress = (e) => {
    if (e.key === "Enter") {
      console.log("[search] confirm...")
      const ga = getInstance()
      ga.sendEvent("search_input", "press_key", this.props.value, 0)
      this.pushResult()
    }
  }
  public onSearchIconClick = (e) => {
    const ga = getInstance()
    ga.sendEvent("search_input", "click-icon", this.props.value, 0)
    this.pushResult()
  }
  public onChange = (e) => {
    if (this.props.onChange) {
      this.props.onChange(e.target.value)
    }
  }
  public onClearSearchText = () => {
    if (this.props.onChange) {
      this.props.onChange("")
    }
  }
  public render() {
    if (!this.props.t) {
      throw new Error("1i8n component not provide")
    }
    const isResultVisible =
      (this.state.isFocus || !!this.props.forceFocus) &&
      this.props.value.length > 0
    return (
      <SearchTextInputContainer onBlur={this.onInputFocus(false)}>
        <form
          onSubmit={preventDefault}
          action="."
          className="SearchTextInputContainer__input-wrap"
        >
          <InputSingleLine
            className={`${
              isResultVisible
                ? "SeachTextInputContainer__input-wrap__input--result-active"
                : ""
            }`}
            autoFocus={this.props.autoFocus}
            onFocus={this.onInputFocus(true)}
            value={this.props.value}
            type="search"
            onChange={this.onChange}
            onKeyPress={this.onKeyPress}
            fluid
            placeholder={this.props.t("search/placeholder")}
          />
          <Icon
            name="search"
            className={`${
              isResultVisible
                ? "SeachTextInputContainer__search-button--result-active"
                : ""
            }`}
            onClick={this.onSearchIconClick}
          />
        </form>
        <SuggestionResultDialog
          t={this.props.t}
          visible={isResultVisible}
          value={this.props.value}
          onClearSearchText={this.onClearSearchText}
        />
      </SearchTextInputContainer>
    )
  }
}

const _providers = {}

function getProvider(uri: string) {
  if (_providers[uri]) { return _providers[uri] }
  _providers[uri] = provider({ uri })(({ children }) => children as any)
  return _providers[uri]
}

export const SearchTextInputStandalone = compose(
  withTranslate,
  withState("isLoading", "setIsLoading", {}),
  withState<any, any, any, any>("value", "onChange", (props) => {
    return props.initValue || ""
  }),
  withState("result", "setResult", { "": [], "books": [], "authors": [] }),
  lifecycle<any, any>({
    componentWillReceiveProps(nextProps) {
      if (this.props.initValue !== nextProps.initValue) {
        this.props.onChange(nextProps.initValue)
      }
    },
    componentDidMount() {
      this.props.onChange(this.props.value)
    }
  }),
  (Component) => {
    return (props) => {
      // if not provide coreGraphQLUrl or server side will not create provider
      if (!props.coreGraphQLUrl) {
        return <Component {...props} />
      }
      const Provider = getProvider(props.coreGraphQLUrl)
      return (
        <Provider>
          <Component {...props} />
        </Provider>
      )
    }
  }
)(SearchTextInput as any) as React.ComponentClass<{
  initValue?: string
  forceFocus?: boolean
  t?: any
  coreGraphQLUrl?: string
}>

export interface SearchInput
  extends React.ComponentClass<{
      autoFocus?: boolean
      forceFocus?: boolean
      initValue?: string,
      coreGraphQLUrl?: string,
    }> {}

export default withTranslate(SearchTextInputStandalone) as SearchInput
