import { useCallback, useEffect, useRef, useState } from "react"
import { Button, Group, ScrollArea, Stack, Text } from "@mantine/core"
import { nowTime, randomId } from "@/shared/lib/log"
import { HOOK_SOURCE } from "../PreviewFrame/constants"
import type { LogEntryType } from "./types"

const EventLog = () => {
  const viewportRef = useRef<HTMLDivElement>(null)

  const [log, setLog] = useState<LogEntryType[]>([])

  useEffect(() => {
    const vp = viewportRef.current
    if (vp) {
      vp.scrollTo({ top: vp.scrollHeight, behavior: "auto" })
    }
  }, [log])

  const appendLog = useCallback(
    (kind: string, text: string, lineClass?: LogEntryType["lineClass"]) => {
      setLog(prev => [
        ...prev,
        { id: randomId(), time: nowTime(), kind, text, lineClass },
      ])
    },
    []
  )

  const clearLog = useCallback(() => setLog([]), [])

  useEffect(() => {
    const onMsg = (e: MessageEvent) => {
      const d = e.data as {
        source?: string
        frame?: string
        kind?: string
        payload?: unknown
      } | null
      if (!d || d.source !== HOOK_SOURCE) return
      const tag = d.frame || "?"
      try {
        const line =
          typeof d.payload === "string"
            ? d.payload
            : JSON.stringify(d.payload, null, 0)
        let lineClass: LogEntryType["lineClass"]
        switch (d.kind) {
          case "error":
            lineClass = "err"
            break
          case "iframe-load":
            lineClass = "nav"
            break
          case "hashchange":
            lineClass = "nav"
            appendLog(
              `[переход]`,
              (d.payload as { href: string }).href,
              lineClass
            )
            break
          case "click":
            lineClass = "nav"
            appendLog(`[клик]`, (d.payload as { target: string }).target)
            break
          default:
            lineClass = undefined
            appendLog(`[${d.kind}:${tag}]`, line, lineClass)
            break
        }
      } catch {
        appendLog(`[message:${tag}]`, String(d))
      }
    }
    window.addEventListener("message", onMsg)
    return () => window.removeEventListener("message", onMsg)
  }, [appendLog])

  return (
    <Stack gap={0} h="100%" mih={0}>
      <Group
        gap="xs"
        p="xs"
        justify="space-between"
        wrap="wrap"
        style={{ borderBottom: "1px solid var(--mantine-color-dark-4)" }}
      >
        <Text size="sm" fw={600}>
          События
        </Text>
        <Group gap="xs">
          <Button size="compact-xs" variant="default" onClick={clearLog}>
            Очистить
          </Button>
        </Group>
      </Group>
      <ScrollArea
        flex={1}
        viewportRef={viewportRef}
        p="xs"
        type="auto"
        offsetScrollbars
      >
        <Stack gap={0}>
          {log.map(e => (
            <Text
              key={e.id}
              component="pre"
              size="xs"
              ff="monospace"
              m={0}
              py={4}
              style={{
                whiteSpace: "pre-wrap",
                wordBreak: "break-word",
                borderBottom: "1px solid var(--mantine-color-dark-6)",
                color:
                  e.lineClass === "err"
                    ? "var(--mantine-color-red-4)"
                    : e.lineClass === "nav"
                      ? "var(--mantine-color-green-4)"
                      : undefined,
              }}
            >
              <Text span c="dimmed" mr="xs">
                {e.time}
              </Text>
              {e.kind} {e.text}
            </Text>
          ))}
        </Stack>
      </ScrollArea>
    </Stack>
  )
}

export default EventLog
