import { css, cx } from "@emotion/css"
import styled from "@emotion/styled"
import Icon from "@aet/icons/macro"
import { groupBy } from "lodash"
import { memo, useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import { useEvent, useInitialState } from "@aet/hooks"
import type * as types from "~/generated/graphql"
import { color, token, vars } from "../../theme"
import { Badge, sass } from "../../panels/Issues"
import { editorNavigation } from "~/options/utils/emitter"
import { useOpenFile } from "~/options/hooks/useOpenFile"
import { ms } from "~/shared/wait"

type Match = types.SearchTabQuery["search"][number]
type SelectedMatchState = ReturnType<typeof useState<Match>>

const Found = styled.span`
  background-color: ${color("#ffdf5d66", "#ffd33d21")};
`

const HighlightedText = memo<{ match: Match }>(({ match }) => {
  const { line, submatch } = match
  return (
    <>
      {line.slice(0, submatch.start)}
      <Found>{submatch.match}</Found>
      {line.slice(submatch.end)}
    </>
  )
})

const LineResult = memo<{
  item: Match
  onRemove(e: React.MouseEvent<SVGSVGElement, MouseEvent>): void
  selectState: SelectedMatchState
}>(({ item, onRemove, selectState: [selected, setSelected] }) => {
  const open = useOpenFile()
  const onClick = useEvent(async () => {
    await open(item.file.id)
    setSelected(item)
    await ms(50)
    editorNavigation.emit({
      fileId: item.file.id,
      position: item.index,
    })
  })

  return (
    <button
      className={cx(
        css`
          align-items: center;
          border: 1px solid transparent;
          cursor: pointer;
          display: flex;
          padding: 2px 14px 2px 2em;
          text-align: left;
          user-select: none;
          width: 100%;
          &.active,
          &:hover {
            background-color: ${vars.backgroundActive};
          }
          &.active {
            border-color: ${token.border.default};
          }
        `,
        { active: selected === item },
      )}
      onClick={onClick}
    >
      <span
        className={css`
          flex-grow: 1;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          opacity: 0.9;
        `}
      >
        <HighlightedText match={item} />
      </span>
      <CloseIcon onClick={onRemove} />
    </button>
  )
})

const FileResult = memo<{
  data: Match[]
  selectState: SelectedMatchState
  onClose(): void
}>(({ data, selectState, onClose }) => {
  const [collapsed, setCollapsed] = useState(false)
  const [list, setList] = useInitialState(data)
  const toggleCollapse = useEvent(() => setCollapsed(!collapsed))

  if (!list.length) {
    return null
  }

  return (
    <div>
      <button
        onClick={toggleCollapse}
        className={css`
          border: none;
          cursor: pointer;
          display: flex;
          align-items: center;
          margin-top: 1px;
          margin-bottom: 0px;
          padding: 3px 13px;
          padding-right: 15px;
          width: 100%;
          text-align: left;

          &:not(:hover) {
            .icons {
              display: none;
            }
          }

          &:hover {
            background-color: ${token.canvas.overlay};
            .badge {
              display: none;
            }
          }
        `}
      >
        <Icon icon={collapsed ? "VscChevronRight" : "VscChevronDown"} />
        {sass}
        <div
          className={css`
            flex: 1;
            margin-left: 2px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          `}
        >
          {list[0].file.name}
        </div>
        <Badge
          className={cx(
            "badge",
            css`
              margin-right: -3px;
            `,
          )}
        >
          {list.length}
        </Badge>
        <CloseIcon className="icons" onClick={onClose} />
      </button>
      <div style={collapsed ? { display: "none" } : undefined}>
        {list.map((item, i) => (
          <LineResult
            item={item}
            key={i}
            selectState={selectState}
            onRemove={e => {
              e.stopPropagation()
              setList(list.filter((_, j) => j !== i))
            }}
          />
        ))}
      </div>
    </div>
  )
})

type Grouped = types.SearchTabQuery["search"][]

export const SearchResults = memo<{ data: types.SearchTabQuery }>(({ data }) => {
  const { t } = useTranslation()
  const { search } = data
  const selectState = useState<Match>()
  const [grouped, setGrouped] = useState<Grouped>([])

  const onClose = useEvent((i: number) => {
    setGrouped(grouped.filter((_, j) => j !== i))
  })

  useEffect(() => {
    setGrouped(Object.values(groupBy(search, v => v.file.id)))
  }, [search])

  return (
    <SearchResultsContainer>
      <div
        className={css`
          font-size: 0.96em;
          padding-left: 15px;
          opacity: 0.6;
        `}
      >
        {t("search.resultCounter", {
          count: search.length,
          fileCount: grouped.length,
        })}
      </div>
      <List>
        {grouped.map((item, i) => (
          <FileResult
            key={i}
            data={item}
            selectState={selectState}
            onClose={() => onClose(i)}
          />
        ))}
      </List>
    </SearchResultsContainer>
  )
})

const SearchResultsContainer = styled.div`
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  overflow: scroll;
`

const List = styled.div`
  border-radius: 5px;
  margin-top: 7px;
  flex-grow: 1;
  line-height: 1.5em;
  overflow: scroll;
`

const CloseIcon = styled(Icon.of("VscClose"))`
  min-width: 1em;
  margin-left: 3px;
`
