import { Show, createEffect, createSignal, onCleanup } from 'solid-js'
import { createShortcut } from '@solid-primitives/keyboard'
import { Portal } from 'solid-js/web'
import { ThemeContextProvider } from '@tanstack/devtools-ui'
import { devtoolsEventClient } from '@tanstack/devtools-client'

import {
  useDevtoolsSettings,
  useHeight,
  usePersistOpen,
  useTheme,
} from './context/use-devtools-context'
import { useDisableTabbing } from './hooks/use-disable-tabbing'
import { TANSTACK_DEVTOOLS } from './utils/storage'
import { getHotkeyPermutations } from './utils/hotkey'
import { Trigger } from './components/trigger'
import { MainPanel } from './components/main-panel'
import { ContentPanel } from './components/content-panel'
import { Tabs } from './components/tabs'
import { TabContent } from './components/tab-content'
import { usePiPWindow } from './context/pip-context'
import { SourceInspector } from './components/source-inspector'

export default function DevTools() {
  const { settings } = useDevtoolsSettings()
  const { setHeight } = useHeight()
  const { persistOpen, setPersistOpen } = usePersistOpen()
  const [rootEl, setRootEl] = createSignal<HTMLDivElement>()
  const [isOpen, setIsOpen] = createSignal(
    settings().defaultOpen || persistOpen(),
  )
  const pip = usePiPWindow()
  let panelRef: HTMLDivElement | undefined = undefined
  const [isResizing, setIsResizing] = createSignal(false)

  const toggleOpen = () => {
    if (pip().pipWindow) {
      return
    }
    const open = isOpen()
    const newState = !open
    setIsOpen(newState)
    setPersistOpen(newState)

    // Emit event when user toggles devtools
    devtoolsEventClient.emit('trigger-toggled', { isOpen: newState })
  }

  // Listen for trigger-toggled events to control devtools
  createEffect(() => {
    const unsubscribe = devtoolsEventClient.on('trigger-toggled', (event) => {
      if (pip().pipWindow) {
        return
      }
      const payload = event.payload as unknown as { isOpen: boolean }
      const shouldBeOpen = payload.isOpen
      if (shouldBeOpen !== isOpen()) {
        setIsOpen(shouldBeOpen)
        setPersistOpen(shouldBeOpen)
      }
    })

    onCleanup(unsubscribe)
  })
  // Used to resize the panel
  const handleDragStart = (
    panelElement: HTMLDivElement | undefined,
    startEvent: MouseEvent,
  ) => {
    if (startEvent.button !== 0) return // Only allow left click for drag
    if (!panelElement) return
    setIsResizing(true)

    const dragInfo = {
      originalHeight: panelElement.getBoundingClientRect().height,
      pageY: startEvent.pageY,
    }

    const run = (moveEvent: MouseEvent) => {
      const delta = dragInfo.pageY - moveEvent.pageY
      const newHeight =
        settings().panelLocation === 'bottom'
          ? dragInfo.originalHeight + delta
          : dragInfo.originalHeight - delta

      setHeight(newHeight)

      if (newHeight < 70) {
        setIsOpen(false)
      } else {
        setIsOpen(true)
      }
    }

    const unsub = () => {
      setIsResizing(false)
      document.removeEventListener('mousemove', run)
      document.removeEventListener('mouseUp', unsub)
    }

    document.addEventListener('mousemove', run)
    document.addEventListener('mouseup', unsub)
  }

  // Handle resizing and padding adjustments
  createEffect(() => {
    if (isOpen()) {
      const previousValue = rootEl()?.parentElement?.style.paddingBottom

      const run = () => {
        if (!panelRef) return
        // const containerHeight = panelRef.getBoundingClientRect().height
        if (rootEl()?.parentElement) {
          setRootEl((prev) => {
            if (prev?.parentElement) {
              // prev.parentElement.style.paddingBottom = `${containerHeight}px`
            }
            return prev
          })
        }
      }

      run()

      if (typeof window !== 'undefined') {
        ;(pip().pipWindow ?? window).addEventListener('resize', run)

        return () => {
          ;(pip().pipWindow ?? window).removeEventListener('resize', run)
          if (rootEl()?.parentElement && typeof previousValue === 'string') {
            setRootEl((prev) => {
              // prev!.parentElement!.style.paddingBottom = previousValue
              return prev
            })
          }
        }
      }
    } else {
      // Reset padding when devtools are closed
      if (rootEl()?.parentElement) {
        setRootEl((prev) => {
          if (prev?.parentElement) {
            prev.parentElement.removeAttribute('style')
          }
          return prev
        })
      }
    }
    return
  })

  createEffect(() => {
    window.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && isOpen()) {
        toggleOpen()
      }
    })
  })
  useDisableTabbing(isOpen)
  createEffect(() => {
    if (rootEl()) {
      const el = rootEl()
      const fontSize = getComputedStyle(el!).fontSize
      el?.style.setProperty('--tsrd-font-size', fontSize)
    }
  })
  createEffect(() => {
    const isEditableTarget = (element: Element | null) => {
      if (!element || !(element instanceof HTMLElement)) return false
      if (element.isContentEditable) return true
      const tagName = element.tagName
      if (
        tagName === 'INPUT' ||
        tagName === 'TEXTAREA' ||
        tagName === 'SELECT'
      ) {
        return true
      }
      return element.getAttribute('role') === 'textbox'
    }

    const permutations = getHotkeyPermutations(settings().openHotkey)

    for (const permutation of permutations) {
      createShortcut(permutation, () => {
        if (isEditableTarget(document.activeElement)) return
        toggleOpen()
      })
    }
  })

  const { theme } = useTheme()

  createEffect(() => {
    if (typeof document === 'undefined') {
      return
    }

    document.documentElement.dataset.tanstackDevtoolsTheme = theme()
  })

  return (
    <ThemeContextProvider theme={theme()}>
      <Portal mount={(pip().pipWindow ?? window).document.body}>
        <div ref={setRootEl} data-testid={TANSTACK_DEVTOOLS}>
          <Show
            when={
              pip().pipWindow !== null
                ? true
                : settings().requireUrlFlag
                  ? window.location.search.includes(settings().urlFlag)
                  : true
            }
          >
            <Trigger isOpen={isOpen} setIsOpen={toggleOpen} />
            <MainPanel isResizing={isResizing} isOpen={isOpen}>
              <ContentPanel
                ref={(ref) => (panelRef = ref)}
                handleDragStart={(e) => handleDragStart(panelRef, e)}
              >
                <Tabs toggleOpen={toggleOpen} />
                <TabContent isOpen={isOpen()} />
              </ContentPanel>
            </MainPanel>
          </Show>
          <SourceInspector />
        </div>
      </Portal>
    </ThemeContextProvider>
  )
}
