import monaco, { MarkerSeverity, type Uri } from "monaco-editor"
import styled from "@emotion/styled"
import { css } from "@emotion/css"
import Icon from "@aet/icons/macro"
import { memo, useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { useReactiveVar } from "@apollo/client"
import { useEvent } from "@aet/hooks"
import { gql, useQuery } from "~/generated/graphql"
import { color, token } from "../theme"
import { getTabs, useSelector } from "../store"
import { editorNavigation } from "../utils/emitter"
import { useOpenFile } from "../hooks/useOpenFile"
import type { ReduxFile } from "../store/state"
import { editorMarkers } from "../editor/Monaco"

const InputNameQuery = gql<"IssueFileNameQuery">`
  query IssueFileNameQuery($id: ID!) {
    file(id: $id) {
      id
      name
    }
  }
`

const SeverityView = memo(({ severity }: { severity: MarkerSeverity }) => {
  switch (severity) {
    case MarkerSeverity.Error:
      return (
        <Icon
          icon="VscError"
          className={css`
            color: #f97583;
          `}
        />
      )
    case MarkerSeverity.Warning:
      return (
        <Icon
          icon="VscWarning"
          className={css`
            color: ${color("#bf8803", "#ffea7f")};
          `}
        />
      )
    case MarkerSeverity.Info:
      return (
        <Icon
          icon="VscInfo"
          className={css`
            color: #3794ff;
          `}
        />
      )
    case MarkerSeverity.Hint:
      return <Icon icon="VscLightbulb" />
    default:
      return <span>❓</span>
  }
})

const Marker = memo(({ marker }: { marker: monaco.editor.IMarker }) => {
  const { code } = marker
  const file = useFileFromUri(marker.resource)
  const open = useOpenFile()

  const onClick = useEvent(() => {
    void open(file.id)
    editorNavigation.emit({
      fileId: file.id,
      position: {
        lineNumber: marker.startLineNumber,
        column: marker.startColumn,
      },
    })
  })

  return (
    <IssueItem data-id={file.id} onClick={onClick}>
      <SeverityView severity={marker.severity} />
      <MarkerMessage>{marker.message}</MarkerMessage>
      <MarkerCode>
        {marker.source}({typeof code === "string" ? code : code?.value})
      </MarkerCode>
      <MarkerPosition>
        [Ln {marker.startLineNumber}, Col {marker.startColumn}]
      </MarkerPosition>
    </IssueItem>
  )
})

function findFile(files: ReduxFile[], uri: Uri) {
  return files.find(x => uri.path.startsWith(`/${x.id}.`))!
}

function useFileFromUri(uri: Uri) {
  const tabs = useSelector(getTabs)
  return findFile(tabs, uri)
}

const FileName = memo(({ uri }: { uri: Uri }) => {
  const { t } = useTranslation()
  const matchingFile = useFileFromUri(uri)
  const { data } = useQuery(InputNameQuery, {
    variables: { id: matchingFile.id },
  })

  return <FileNameContainer>{data?.file.name ?? t("file.untitled")}</FileNameContainer>
})

const FileIssue = memo<{ uri: Uri; markers: monaco.editor.IMarker[] }>(
  ({ uri, markers }) => {
    const [collapsed, setCollapsed] = useState(false)

    if (!markers.length) return null

    return (
      <div>
        <FileIssueTitle onClick={() => setCollapsed(x => !x)}>
          <Icon icon={collapsed ? "VscChevronRight" : "VscChevronDown"} />
          {sass}
          <FileName uri={uri} /> <Badge>{markers.length}</Badge>
        </FileIssueTitle>
        {!collapsed && (
          <div>
            {markers.map((marker, i) => (
              <Marker marker={marker} key={i} />
            ))}
          </div>
        )}
      </div>
    )
  },
)

export const Issues = memo<ClassNameProp>(({ className }) => {
  const { t } = useTranslation()
  const tabs = useSelector(getTabs)

  const changedMarkers = useReactiveVar(editorMarkers)
  const markersMap = useMemo(
    () =>
      new Map(
        changedMarkers.map(uri => [
          uri,
          monaco.editor.getModelMarkers({ resource: uri }),
        ]),
      ),
    [changedMarkers],
  )

  if (!markersMap.size) {
    return (
      <IssuesContainer className={className}>
        <div
          className={css`
            margin: 12px 14px;
          `}
        >
          {t("issues.noIssuesFound")}
        </div>
      </IssuesContainer>
    )
  }

  return (
    <IssuesContainer className={className}>
      {Array.from(markersMap.entries()).map(([uri, markers]) =>
        findFile(tabs, uri) ? (
          <FileIssue uri={uri} markers={markers} key={uri.path} />
        ) : null,
      )}
    </IssuesContainer>
  )
})

const IssuesContainer = styled.div`
  margin: 8px 7px;
  flex-grow: 1;
  line-height: 1.3em;
`
const Hoverable = styled.div`
  border-radius: 4px;
  &:hover {
    background-color: ${color("#eaeef280", "#6e76811a")};
  }
`
const FileIssueTitle = styled(Hoverable)`
  display: flex;
  align-items: center;
  line-height: 1.3em;
  padding: 3px 10px;
  margin-top: 5px;
  cursor: pointer;
`
const FileNameContainer = styled.div`
  margin-left: 5px;
  margin-right: 5px;
  user-select: none;
`
const IssueItem = styled(Hoverable)`
  cursor: pointer;
  display: flex;
  align-items: center;
  padding: 3px 1px;
  padding-left: 45px;
  user-select: none;
`
const MarkerMessage = styled.div`
  margin-left: 6px;
`
const MarkerCode = styled.div`
  opacity: 0.7;
  margin-left: 5px;
`
const MarkerPosition = styled.div`
  opacity: 0.7;
  margin-left: 5px;
`
export const Badge = styled.div`
  background-color: ${token.accent.emphasis};
  color: ${color("#fff", "#f0f6fc")};
  min-width: 1.6em;
  text-align: center;
  border-radius: 10px;
  font-size: 0.9em;
`

// https://github.com/PKief/vscode-material-icon-theme/blob/main/LICENSE.md
// The MIT License (MIT). Copyright (c) 2021 Philipp Kief
export const sass = (
  <svg
    viewBox="0 0 500 500"
    className={css`
      width: 1.2em;
      margin-left: 3px;
    `}
  >
    <path
      d="M419.047 96.227C406.855 48.39 327.54 32.67 252.472 59.336c-44.68 15.876-93.029 40.785-127.81 73.31-41.349 38.675-47.943 72.329-45.216 86.396 9.583 49.621 77.585 82.068 105.535 106.125v.144c-8.246 4.051-68.565 34.585-82.684 65.8-14.893 32.932 2.372 56.556 13.804 59.742 35.424 9.858 71.765-7.866 91.312-37.01 18.852-28.12 17.279-64.422 9.085-82.488 11.3-2.976 24.476-4.313 41.218-2.36 47.248 5.52 56.517 35.017 54.747 47.367s-11.681 19.14-14.998 21.185-4.326 2.767-4.05 4.287c.406 2.216 1.94 2.137 4.758 1.652 3.894-.655 24.804-10.042 25.709-32.827 1.14-28.934-26.587-61.302-75.684-60.45-20.216.354-32.933 2.268-42.123 5.69a82.505 82.505 0 0 0-2.084-2.308c-30.35-32.382-86.46-55.285-84.088-98.823.866-15.824 6.372-57.5 107.817-108.053 83.104-41.414 149.638-30.009 161.135-4.759 16.427 36.079-35.554 103.137-121.857 112.812-32.88 3.684-50.199-9.06-54.499-13.805-4.536-4.995-5.204-5.218-6.909-4.287-2.753 1.534-1.01 5.939 0 8.574 2.583 6.712 13.15 18.603 31.176 24.516 15.863 5.204 54.459 8.062 101.157-9.99 52.282-20.255 93.12-76.523 81.124-123.549zM196.584 339.995c3.92 14.5 3.487 28.016-.564 40.247a65.289 65.289 0 0 1-3.225 7.97c-3.12 6.477-7.315 12.534-12.441 18.132-15.654 17.07-37.508 23.533-46.882 18.092-10.12-5.873-5.047-29.943 13.084-49.11 19.52-20.635 47.602-33.902 47.602-33.902l-.039-.08 2.465-1.35z"
      fill="#ec407a"
      stroke="#ec407a"
      strokeWidth="16.287"
    />
  </svg>
)
