/**
 * 窗口和文件系统操作 IPC 处理器
 */

import { ipcMain, app, dialog, clipboard, shell, nativeTheme } from 'electron'
import * as fs from 'fs/promises'
import type { IpcContext } from './types'
import { simulateUpdateDialog, manualCheckForUpdates } from '../update'
import { t } from '../i18n'
import {
  applyCurrentTitleBarOverlay,
  applyTitleBarOverlayColor,
  resetCurrentTitleBarOverlayColor,
} from '../window-titlebar'
import { getDesktopAppVersion } from '../runtime-compat'

type AppWithQuitFlag = typeof app & { isQuiting?: boolean }
// 通过类型扩展记录应用退出意图，避免使用 @ts-ignore。
const appWithQuitFlag = app as AppWithQuitFlag

const REMOTE_CONFIG_ALLOWED_DOMAINS = ['chatlab.fun', '1app.top']
const REMOTE_CONFIG_TIMEOUT_MS = 8000
const REMOTE_CONFIG_MAX_BYTES = 1024 * 1024 // 1MB

function isAllowedRemoteConfigUrl(rawUrl: string): boolean {
  let parsed: URL
  try {
    parsed = new URL(rawUrl)
  } catch {
    return false
  }

  if (parsed.protocol !== 'https:') return false
  if (parsed.username || parsed.password) return false
  if (parsed.port && parsed.port !== '443') return false

  const hostname = parsed.hostname.toLowerCase()
  return REMOTE_CONFIG_ALLOWED_DOMAINS.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))
}

/**
 * 注册窗口和文件系统操作 IPC 处理器
 */
export function registerWindowHandlers(ctx: IpcContext): void {
  const { win } = ctx

  // ==================== 窗口操作 ====================
  ipcMain.on('window-min', (ev) => {
    ev.preventDefault()
    win.minimize()
  })

  ipcMain.on('window-maxOrRestore', (ev) => {
    const winSizeState = win.isMaximized()
    if (winSizeState) {
      win.restore()
    } else {
      win.maximize()
    }
    ev.reply('windowState', win.isMaximized())
  })

  ipcMain.on('window-restore', () => {
    win.restore()
  })

  ipcMain.on('window-hide', () => {
    win.hide()
  })

  ipcMain.on('window-close', () => {
    win.close()
    appWithQuitFlag.isQuiting = true
    app.quit()
  })

  ipcMain.on('window-resize', (_, data) => {
    if (data.resize) {
      win.setResizable(true)
    } else {
      win.setSize(1180, 752)
      win.setResizable(false)
    }
  })

  ipcMain.on('open-devtools', () => {
    win.webContents.openDevTools()
  })

  // 设置主题模式
  ipcMain.on('window:setThemeSource', (_, mode: 'system' | 'light' | 'dark') => {
    nativeTheme.themeSource = mode

    // Windows 上动态更新 overlay 颜色以匹配主题
    if (process.platform === 'win32' && win) {
      resetCurrentTitleBarOverlayColor()
      applyCurrentTitleBarOverlay(win, nativeTheme.shouldUseDarkColors)
    }
  })

  ipcMain.on('window:setTitleBarOverlayColor', (_, color: string) => {
    if (!/^#[0-9a-f]{6}$/i.test(color)) return

    if (process.platform === 'win32' && win) {
      applyTitleBarOverlayColor(win, color)
    }
  })

  // ==================== 应用信息 ====================
  ipcMain.handle('app:getVersion', () => {
    return getDesktopAppVersion(app.getVersion())
  })

  // 重启应用
  ipcMain.handle('app:relaunch', () => {
    app.relaunch()
    app.quit()
  })

  // 获取远程配置（支持 JSON 和纯文本/Markdown）
  ipcMain.handle('app:fetchRemoteConfig', async (_, url: string) => {
    const normalizedUrl = typeof url === 'string' ? url.trim() : ''
    if (!isAllowedRemoteConfigUrl(normalizedUrl)) {
      return { success: false, error: 'URL is not allowed' }
    }

    const abortController = new AbortController()
    const timeout = setTimeout(() => abortController.abort(), REMOTE_CONFIG_TIMEOUT_MS)

    try {
      // 使用 manual 重定向模式，手动验证每个重定向目标
      let currentUrl = normalizedUrl
      let response = await fetch(currentUrl, {
        signal: abortController.signal,
        redirect: 'manual',
      })

      // 处理重定向链（最多跟随3次重定向，避免无限循环）
      let redirectCount = 0
      const maxRedirects = 3

      while (response.status >= 300 && response.status < 400 && redirectCount < maxRedirects) {
        redirectCount++

        const location = response.headers.get('location')
        if (!location) {
          return { success: false, error: `Redirect response without location header (hop ${redirectCount})` }
        }

        // 构建完整的重定向 URL
        const redirectUrl = new URL(location, currentUrl).href
        if (!isAllowedRemoteConfigUrl(redirectUrl)) {
          return { success: false, error: `Redirect URL is not allowed (hop ${redirectCount}): ${redirectUrl}` }
        }

        // 跟随重定向
        currentUrl = redirectUrl
        response = await fetch(currentUrl, {
          signal: abortController.signal,
          redirect: 'manual',
        })
      }

      // 检查是否超过最大重定向次数（严格大于，允许恰好等于最大次数）
      if (redirectCount > maxRedirects) {
        return { success: false, error: `Too many redirects (exceeded ${maxRedirects})` }
      }

      // 验证最终响应的 URL
      const finalUrl = response.url || currentUrl
      if (!isAllowedRemoteConfigUrl(finalUrl)) {
        return { success: false, error: 'Final URL is not allowed' }
      }

      const contentType = response.headers.get('content-type') || ''
      const contentLength = Number(response.headers.get('content-length') || 0)

      if (Number.isFinite(contentLength) && contentLength > REMOTE_CONFIG_MAX_BYTES) {
        return { success: false, error: 'Response is too large' }
      }

      if (!response.ok) {
        return { success: false, error: `HTTP ${response.status}: ${response.statusText}` }
      }

      const buffer = Buffer.from(await response.arrayBuffer())
      if (buffer.length > REMOTE_CONFIG_MAX_BYTES) {
        return { success: false, error: 'Response is too large' }
      }

      // 根据 Content-Type 或 URL 后缀决定解析方式
      const isJson = contentType.includes('application/json') || finalUrl.endsWith('.json')

      if (isJson) {
        const data = JSON.parse(buffer.toString('utf-8'))
        return { success: true, data }
      } else {
        // 纯文本/Markdown 等其他格式
        const data = buffer.toString('utf-8')
        return { success: true, data }
      }
    } catch (error) {
      if (error instanceof Error && error.name === 'AbortError') {
        return { success: false, error: 'Request timeout' }
      }
      return { success: false, error: String(error) }
    } finally {
      clearTimeout(timeout)
    }
  })

  // ==================== 开机自启动 ====================
  ipcMain.handle('app:getOpenAtLogin', () => {
    if (!app.isPackaged) return false
    const { openAtLogin } = app.getLoginItemSettings()
    return openAtLogin
  })

  ipcMain.handle('app:setOpenAtLogin', (_, enabled: boolean) => {
    if (!app.isPackaged) return { success: false, error: 'Not available in dev mode' }
    try {
      app.setLoginItemSettings({ openAtLogin: enabled })
      return { success: true }
    } catch (error) {
      return { success: false, error: String(error) }
    }
  })

  // ==================== 更新检查 ====================
  ipcMain.on('check-update', () => {
    // 手动检查更新（即使是预发布版本也会提示）
    manualCheckForUpdates()
  })

  // 模拟更新弹窗（仅开发模式使用）
  ipcMain.on('simulate-update', () => {
    if (!app.isPackaged) {
      simulateUpdateDialog(win)
    }
  })

  // ==================== 通用工具 ====================
  ipcMain.handle('show-message', (event, args) => {
    event.sender.send('show-message', args)
  })

  // 复制到剪贴板（文本）
  ipcMain.handle('copyData', async (_, data) => {
    try {
      clipboard.writeText(data)
      return true
    } catch (error) {
      console.error('Copy operation error:', error)
      return false
    }
  })

  // 复制图片到剪贴板（base64 data URL）
  ipcMain.handle('copyImage', async (_, dataUrl: string) => {
    try {
      // 从 data URL 中提取 base64 数据
      const base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, '')
      const imageBuffer = Buffer.from(base64Data, 'base64')
      // 使用 nativeImage 创建图片并写入剪贴板
      const { nativeImage } = await import('electron')
      const image = nativeImage.createFromBuffer(imageBuffer)
      clipboard.writeImage(image)
      return { success: true }
    } catch (error) {
      console.error('Image copy error:', error)
      return { success: false, error: String(error) }
    }
  })

  // ==================== 文件系统操作 ====================
  // 选择文件夹
  ipcMain.handle('selectDir', async (_, defaultPath = '') => {
    try {
      const { canceled, filePaths } = await dialog.showOpenDialog({
        title: t('dialog.selectDirectory'),
        defaultPath: defaultPath || app.getPath('documents'),
        properties: ['openDirectory', 'createDirectory'],
        buttonLabel: t('dialog.selectFolder'),
      })
      if (!canceled) {
        return filePaths[0]
      }
      return null
    } catch (err) {
      console.error(t('dialog.selectFolderError'), err)
      throw err
    }
  })

  // 检查文件是否存在
  ipcMain.handle('checkFileExist', async (_, filePath) => {
    try {
      await fs.access(filePath)
      return true
    } catch {
      return false
    }
  })

  // 在文件管理器中打开
  ipcMain.handle('openInFolder', async (_, path) => {
    try {
      await fs.access(path)
      await shell.showItemInFolder(path)
      return true
    } catch (error) {
      console.error('Error opening directory:', error)
      return false
    }
  })

  // 显示打开对话框（通用）
  ipcMain.handle('dialog:showOpenDialog', async (_, options) => {
    try {
      return await dialog.showOpenDialog(options)
    } catch (error) {
      console.error('Failed to show dialog:', error)
      throw error
    }
  })
}
