import { usePreference } from '@data/hooks/usePreference'
import { loggerService } from '@logger'
import type { DidNavigateInPageEvent, WebviewTag } from 'electron'
import { memo, useCallback, useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next'

const logger = loggerService.withContext('WebviewContainer')

/**
 * WebviewContainer is a component that renders a webview element.
 * It is used in the MiniAppPopupContainer component.
 * The webcontent can be remain in memory
 */
const WebviewContainer = memo(
  ({
    appid,
    url,
    onSetRefCallback,
    onLoadedCallback,
    onNavigateCallback
  }: {
    appid: string
    url: string
    onSetRefCallback: (appid: string, element: WebviewTag | null) => void
    onLoadedCallback: (appid: string) => void
    onNavigateCallback: (appid: string, url: string) => void
  }) => {
    const webviewRef = useRef<WebviewTag | null>(null)
    const { t } = useTranslation()
    const [enableSpellCheck] = usePreference('app.spell_check.enabled')
    const [openLinkExternal] = usePreference('feature.mini_app.open_link_external')
    const handleRef = useCallback(
      (element: WebviewTag | null) => {
        onSetRefCallback(appid, element)
        if (element) {
          webviewRef.current = element
        } else {
          webviewRef.current = null
        }
      },
      [appid, onSetRefCallback]
    )

    useEffect(() => {
      if (!webviewRef.current) return

      let loadCallbackFired = false

      const handleLoaded = () => {
        logger.debug(`WebView did-finish-load for app: ${appid}`)
        // Only fire callback once per load cycle
        if (!loadCallbackFired) {
          loadCallbackFired = true
          // Small delay to ensure content is actually visible
          setTimeout(() => {
            logger.debug(`Calling onLoadedCallback for app: ${appid}`)
            onLoadedCallback(appid)
          }, 100)
        }
      }

      // Additional callback for when page is ready to show
      const handleReadyToShow = () => {
        logger.debug(`WebView ready-to-show for app: ${appid}`)
        if (!loadCallbackFired) {
          loadCallbackFired = true
          logger.debug(`Calling onLoadedCallback from ready-to-show for app: ${appid}`)
          onLoadedCallback(appid)
        }
      }

      const handleNavigate = (event: DidNavigateInPageEvent) => {
        onNavigateCallback(appid, event.url)
      }

      const handleDomReady = () => {
        const webviewId = webviewRef.current?.getWebContentsId()
        if (webviewId) {
          void window.api?.webview?.setSpellCheckEnabled?.(webviewId, enableSpellCheck)
          // Set link opening behavior for this webview
          void window.api?.webview?.setOpenLinkExternal?.(webviewId, openLinkExternal)
        }
      }

      const handleStartLoading = () => {
        // Reset callback flag when starting a new load
        loadCallbackFired = false
      }

      webviewRef.current.addEventListener('did-start-loading', handleStartLoading)
      webviewRef.current.addEventListener('dom-ready', handleDomReady)
      webviewRef.current.addEventListener('did-finish-load', handleLoaded)
      webviewRef.current.addEventListener('ready-to-show', handleReadyToShow)
      webviewRef.current.addEventListener('did-navigate-in-page', handleNavigate)

      // we set the url when the webview is ready
      webviewRef.current.src = url

      return () => {
        webviewRef.current?.removeEventListener('did-start-loading', handleStartLoading)
        webviewRef.current?.removeEventListener('dom-ready', handleDomReady)
        webviewRef.current?.removeEventListener('did-finish-load', handleLoaded)
        webviewRef.current?.removeEventListener('ready-to-show', handleReadyToShow)
        webviewRef.current?.removeEventListener('did-navigate-in-page', handleNavigate)
      }
      // because the appid and url are enough, no need to add onLoadedCallback
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [appid, url])

    // Setup keyboard shortcuts handler for print and save
    useEffect(() => {
      if (!webviewRef.current) return

      const unsubscribe = window.api?.webview?.onFindShortcut?.(async (payload) => {
        // Get webviewId when event is triggered
        const webviewId = webviewRef.current?.getWebContentsId()

        // Only handle events for this webview
        if (!webviewId || payload.webviewId !== webviewId) return

        const key = payload.key?.toLowerCase()
        const isModifier = payload.control || payload.meta

        if (!isModifier || !key) return

        try {
          if (key === 'p') {
            // Print to PDF
            logger.info(`Printing webview ${appid} to PDF`)
            const filePath = await window.api.webview.printToPDF(webviewId)
            if (filePath) {
              window.toast?.success?.(t('miniApp.shortcut.pdf_saved', { path: filePath }))
              logger.info(`PDF saved to: ${filePath}`)
            }
          } else if (key === 's') {
            // Save as HTML
            logger.info(`Saving webview ${appid} as HTML`)
            const filePath = await window.api.webview.saveAsHTML(webviewId)
            if (filePath) {
              window.toast?.success?.(t('miniApp.shortcut.html_saved', { path: filePath }))
              logger.info(`HTML saved to: ${filePath}`)
            }
          }
        } catch (error) {
          logger.error(`Failed to handle shortcut for webview ${appid}:`, error as Error)
          window.toast?.error?.(t('miniApp.shortcut.failed', { message: (error as Error).message }))
        }
      })

      return () => {
        unsubscribe?.()
      }
    }, [appid, t])

    // Update webview settings when they change
    useEffect(() => {
      if (!webviewRef.current) return

      try {
        const webviewId = webviewRef.current.getWebContentsId()
        if (webviewId) {
          void window.api?.webview?.setSpellCheckEnabled?.(webviewId, enableSpellCheck)
          void window.api?.webview?.setOpenLinkExternal?.(webviewId, openLinkExternal)
        }
      } catch (error) {
        // WebView may not be ready yet, settings will be applied in dom-ready event
        logger.debug(`WebView ${appid} not ready for settings update`)
      }
    }, [appid, openLinkExternal, enableSpellCheck])

    const WebviewStyle: React.CSSProperties = {
      width: '100%',
      height: '100%',
      backgroundColor: 'var(--color-background)',
      display: 'inline-flex'
    }

    return (
      <webview
        key={appid}
        ref={handleRef}
        data-mini-app-id={appid}
        style={WebviewStyle}
        allowpopups={true}
        partition="persist:webview"
        useragent={
          appid === 'google'
            ? 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)  Safari/537.36'
            : undefined
        }
      />
    )
  }
)

export default WebviewContainer
