import browser from 'webextension-polyfill'
import { isLikelyDownloadUrl, normalizeUrl } from '../lib/downloadIntent'

const CAPTURE_TTL_MS = 8000
const captureInFlight = new Map<string, number>()

function pruneCaptureInFlight(): void {
  const now = Date.now()
  for (const [url, expiresAt] of captureInFlight.entries()) {
    if (expiresAt <= now) captureInFlight.delete(url)
  }
}

async function sendCapture(url: string, referer: string): Promise<boolean> {
  const normalized = normalizeUrl(url, window.location.href)
  if (!normalized) return false

  pruneCaptureInFlight()
  if (captureInFlight.has(normalized)) return true
  captureInFlight.set(normalized, Date.now() + CAPTURE_TTL_MS)

  try {
    const result = (await browser.runtime.sendMessage({
      type: 'capture-link-download',
      url: normalized,
      referer: referer || document.referrer || window.location.href,
    })) as { ok?: boolean }
    if (result?.ok) return true
  } catch {
    // ignored
  }

  captureInFlight.delete(normalized)
  return false
}

function findAnchor(target: EventTarget | null): HTMLAnchorElement | null {
  if (!target) return null
  if (target instanceof HTMLAnchorElement) return target
  if (target instanceof Element) return target.closest('a[href]') as HTMLAnchorElement | null
  return null
}

function shouldIgnoreHotkey(event: MouseEvent | KeyboardEvent): boolean {
  return !!(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
}

async function interceptAnchorEvent(event: MouseEvent): Promise<void> {
  if (event.defaultPrevented) return
  if (shouldIgnoreHotkey(event)) return

  const anchor = findAnchor(event.target)
  if (!anchor) return
  const href = anchor.href || ''
  if (!href || !isLikelyDownloadUrl(href, window.location.href)) return

  event.preventDefault()
  event.stopImmediatePropagation()
  event.stopPropagation()
  await sendCapture(href, document.referrer || window.location.href)
}

function interceptMouseLike(event: MouseEvent): void {
  const anchor = findAnchor(event.target)
  if (!anchor) return
  const href = anchor.href || ''
  if (!href || !isLikelyDownloadUrl(href, window.location.href)) return
  if (shouldIgnoreHotkey(event)) return

  event.preventDefault()
  event.stopImmediatePropagation()
  event.stopPropagation()
  void sendCapture(href, document.referrer || window.location.href)
}

document.addEventListener('pointerdown', (event: PointerEvent) => {
  if (event.button !== 0) return
  interceptMouseLike(event)
}, true)

document.addEventListener('mousedown', (event: MouseEvent) => {
  if (event.button !== 0) return
  interceptMouseLike(event)
}, true)

document.addEventListener('click', (event: MouseEvent) => {
  if (event.button !== 0) return
  void interceptAnchorEvent(event)
}, true)

document.addEventListener('keydown', (event: KeyboardEvent) => {
  if (event.key !== 'Enter') return
  if (event.defaultPrevented) return
  if (shouldIgnoreHotkey(event)) return

  const anchor = findAnchor(event.target)
  if (!anchor) return
  const href = anchor.href || ''
  if (!href || !isLikelyDownloadUrl(href, window.location.href)) return

  event.preventDefault()
  event.stopImmediatePropagation()
  event.stopPropagation()
  void sendCapture(href, document.referrer || window.location.href)
}, true)

document.addEventListener('auxclick', (event: MouseEvent) => {
  if (event.button !== 1) return
  void interceptAnchorEvent(event)
}, true)

function installProgrammaticInterceptors(): void {
  try {
    const originalOpen = window.open.bind(window)
    window.open = function gomdownInterceptOpen(url?: string | URL, target?: string, features?: string): Window | null {
      const raw = String(url || '').trim()
      if (raw && isLikelyDownloadUrl(raw, window.location.href)) {
        void sendCapture(raw, window.location.href)
        return null
      }
      return originalOpen(url as string, target, features)
    }
  } catch {
    // ignored
  }

  try {
    const originalAnchorClick = HTMLAnchorElement.prototype.click
    HTMLAnchorElement.prototype.click = function gomdownInterceptAnchorClick(): void {
      const href = this.href || this.getAttribute('href') || ''
      if (href && isLikelyDownloadUrl(href, window.location.href)) {
        void sendCapture(href, document.referrer || window.location.href)
        return
      }
      originalAnchorClick.call(this)
    }
  } catch {
    // ignored
  }
}

installProgrammaticInterceptors()

let ytOverlayRoot: HTMLDivElement | null = null
let ytOverlayStatus: HTMLDivElement | null = null
let ytOverlayBusy = false
let ytUrlWatcherTimer: number | null = null
let lastObservedUrl = window.location.href

function isYoutubeWatchPage(url: string): boolean {
  try {
    const parsed = new URL(url)
    if (parsed.hostname !== 'www.youtube.com' && parsed.hostname !== 'youtube.com') return false
    return parsed.pathname === '/watch' && parsed.searchParams.has('v')
  } catch {
    return false
  }
}

function setYtOverlayStatus(message: string, tone: 'ok' | 'error' | 'idle' = 'idle'): void {
  if (!ytOverlayStatus) return
  ytOverlayStatus.textContent = message
  if (tone === 'ok') ytOverlayStatus.style.color = '#8ff0a4'
  else if (tone === 'error') ytOverlayStatus.style.color = '#ff9b9b'
  else ytOverlayStatus.style.color = '#aeb7d8'
}

async function enqueueCurrentYoutubePage(): Promise<void> {
  if (ytOverlayBusy) return
  ytOverlayBusy = true
  setYtOverlayStatus('gdown으로 전송 중...')
  try {
    const result = (await browser.runtime.sendMessage({
      type: 'page:enqueue-ytdlp-url',
      url: window.location.href,
      referer: window.location.href,
    })) as { ok?: boolean; error?: string }
    if (result?.ok) {
      setYtOverlayStatus('다운로드 모달로 전송됨', 'ok')
    } else {
      setYtOverlayStatus(`전송 실패: ${result?.error || 'unknown error'}`, 'error')
    }
  } catch (error) {
    setYtOverlayStatus(`전송 실패: ${String(error)}`, 'error')
  } finally {
    ytOverlayBusy = false
  }
}

function removeYoutubeOverlay(): void {
  if (ytOverlayRoot) {
    ytOverlayRoot.remove()
    ytOverlayRoot = null
    ytOverlayStatus = null
  }
}

function ensureYoutubeOverlay(): void {
  if (window.top !== window.self) return
  if (!isYoutubeWatchPage(window.location.href)) {
    removeYoutubeOverlay()
    return
  }
  if (ytOverlayRoot) return

  const root = document.createElement('div')
  root.id = 'gomdown-youtube-overlay'
  root.style.position = 'fixed'
  root.style.right = '20px'
  root.style.bottom = '24px'
  root.style.zIndex = '2147483647'
  root.style.background = 'rgba(17, 21, 32, 0.94)'
  root.style.border = '1px solid rgba(133, 148, 195, 0.35)'
  root.style.borderRadius = '12px'
  root.style.padding = '10px'
  root.style.boxShadow = '0 8px 24px rgba(0, 0, 0, 0.28)'
  root.style.backdropFilter = 'blur(6px)'
  root.style.width = '220px'
  root.style.fontFamily = 'ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif'
  root.style.color = '#e8edff'

  const title = document.createElement('div')
  title.textContent = 'Gdown Helper'
  title.style.fontSize = '12px'
  title.style.fontWeight = '700'
  title.style.marginBottom = '8px'

  const action = document.createElement('button')
  action.type = 'button'
  action.textContent = '이 영상 다운로드'
  action.style.width = '100%'
  action.style.height = '34px'
  action.style.border = '1px solid #5a69f0'
  action.style.borderRadius = '8px'
  action.style.background = '#5a69f0'
  action.style.color = '#ffffff'
  action.style.fontSize = '12px'
  action.style.fontWeight = '700'
  action.style.cursor = 'pointer'
  action.addEventListener('click', () => {
    void enqueueCurrentYoutubePage()
  })

  const status = document.createElement('div')
  status.textContent = '클릭 시 gdown 다운로드 모달로 연결'
  status.style.fontSize = '11px'
  status.style.marginTop = '8px'
  status.style.lineHeight = '1.35'
  status.style.color = '#aeb7d8'

  root.appendChild(title)
  root.appendChild(action)
  root.appendChild(status)
  document.documentElement.appendChild(root)

  ytOverlayRoot = root
  ytOverlayStatus = status
}

function watchYoutubeRouteChanges(): void {
  if (ytUrlWatcherTimer !== null) return
  ytUrlWatcherTimer = window.setInterval(() => {
    const current = window.location.href
    if (current === lastObservedUrl) return
    lastObservedUrl = current
    ensureYoutubeOverlay()
  }, 800)

  window.addEventListener('popstate', () => {
    lastObservedUrl = window.location.href
    ensureYoutubeOverlay()
  })

  document.addEventListener('yt-navigate-finish', () => {
    lastObservedUrl = window.location.href
    ensureYoutubeOverlay()
  })
}

ensureYoutubeOverlay()
watchYoutubeRouteChanges()
