import { app, shell, BrowserWindow, ipcMain, Tray, Menu, nativeImage, WebContentsView, IpcMainEvent, dialog, screen } from 'electron'
import { basename, extname, join } from 'path'
import { fileURLToPath } from 'url'
import { autoUpdater } from 'electron-updater'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import { mkdirSync, appendFileSync, existsSync, writeFileSync } from 'fs'
import { writeFile } from 'fs/promises'
// --- 日志管理 ---
let logDir: string = ''

function ensureLogDir(): void {
  if (!logDir) {
    logDir = join(app.getPath('userData'), 'logs')
  }
  if (!existsSync(logDir)) {
    mkdirSync(logDir, { recursive: true })
  }
}

function writeLog(message: string) {
  ensureLogDir()
  const date = new Date()
  const fileName = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}.log`
  const logPath = join(logDir, fileName)

  try {
    appendFileSync(logPath, message + '\n', 'utf-8')
  } catch (err) {
    console.error('Failed to write log:', err)
  }
}

ipcMain.on('log-message', (_, message) => {
  writeLog(message)
})

let mainWindow: BrowserWindow | null = null
let tray: Tray | null = null
let isQuitting = false
let blinkInterval: NodeJS.Timeout | null = null
let trayPopupWindow: BrowserWindow | null = null
let trayPopupHideTimer: NodeJS.Timeout | null = null
let trayHoverCheckTimer: NodeJS.Timeout | null = null

interface UnreadInfo {
  name: string
  content: string
  count: number
}
const unreadMap = new Map<number, UnreadInfo>()

/** 渲染进程通过 GET /messages/unread-count 同步的总未读数（标题/任务栏角标）；未同步时回退为 unreadMap 累加 */
let appUnreadTotalFromApi: number | null = null

function isHttpUrl(url: string): boolean {
  try {
    const u = new URL(url.trim())
    return u.protocol === 'http:' || u.protocol === 'https:'
  } catch {
    return false
  }
}

function sanitizeFilename(name: string): string {
  return name.replace(/[<>:"/\\|?*\x00-\x1f]/g, '_').slice(0, 120) || 'file'
}

function extFromUrlOrData(url: string, fallback: string): string {
  if (url.startsWith('data:')) {
    const mime = /^data:([^;]+);/i.exec(url)?.[1]?.toLowerCase() || ''
    if (mime.includes('jpeg')) return '.jpg'
    if (mime.includes('png')) return '.png'
    if (mime.includes('gif')) return '.gif'
    if (mime.includes('webp')) return '.webp'
    if (mime.includes('mp4')) return '.mp4'
    if (mime.includes('webm')) return '.webm'
    return fallback
  }
  try {
    const pathname = new URL(url.trim()).pathname
    const e = extname(pathname).toLowerCase()
    if (e && e.length <= 8) return e
  } catch {
    // ignore
  }
  return fallback
}

/** 下载媒体到临时目录后用系统默认应用打开（避免内嵌 data: 预览阻塞主进程） */
async function downloadMediaToTempAndOpen(url: string, suggestedName: string): Promise<void> {
  const base = sanitizeFilename(basename(suggestedName || 'media'))
  let ext = extname(base)
  if (!ext) {
    ext = extFromUrlOrData(url, '.bin')
  }
  const nameWithoutExt = base.replace(/\.[^.]+$/, '') || 'media'
  const fileName = `${nameWithoutExt}-${Date.now()}${ext}`

  const dir = join(app.getPath('temp'), 'yunzhu-im-open')
  mkdirSync(dir, { recursive: true })
  const filePath = join(dir, fileName)

  if (url.startsWith('data:')) {
    const comma = url.indexOf(',')
    if (comma === -1) throw new Error('无效的媒体数据')
    const header = url.slice(0, comma)
    const payload = url.slice(comma + 1)
    const isBase64 = /;base64/i.test(header)
    const buffer = isBase64 ? Buffer.from(payload, 'base64') : Buffer.from(decodeURIComponent(payload), 'utf-8')
    await writeFile(filePath, buffer)
  } else if (url.startsWith('file://')) {
    const localPath = fileURLToPath(url)
    const err = await shell.openPath(localPath)
    if (err) throw new Error(err)
    return
  } else if (isHttpUrl(url)) {
    const res = await fetch(url)
    if (!res.ok) throw new Error(`下载失败: HTTP ${res.status}`)
    const buf = Buffer.from(await res.arrayBuffer())
    await writeFile(filePath, buf)
  } else {
    throw new Error('不支持的媒体地址')
  }

  const err = await shell.openPath(filePath)
  if (err) throw new Error(err)
}

// --- 浏览器视图管理器 ---
interface TabInfo {
  id: string
  url: string
  title: string
  view: WebContentsView
}

class ViewManager {
  private window: BrowserWindow
  private tabs: Map<string, TabInfo> = new Map()
  private activeTabId: string | null = null
  private bounds: Electron.Rectangle = { x: 0, y: 78, width: 1024, height: 600 }

  constructor(window: BrowserWindow) {
    this.window = window
  }

  createTab(url: string, active: boolean = true): string {
    const view = new WebContentsView({
      webPreferences: {
        sandbox: false,
        nodeIntegration: false,
        contextIsolation: true,
      }
    })

    const id = Date.now().toString() + Math.random().toString(36).substr(2, 9)

    view.webContents.on('did-start-loading', () => {
      if (!this.window.isDestroyed()) {
        this.window.webContents.send('tab-update', id, { isLoading: true })
      }
    })

    view.webContents.on('did-stop-loading', () => {
      if (!this.window.isDestroyed()) {
        this.window.webContents.send('tab-update', id, {
          isLoading: false,
          canGoBack: view.webContents.navigationHistory.canGoBack(),
          canGoForward: view.webContents.navigationHistory.canGoForward(),
          url: view.webContents.getURL(),
          title: view.webContents.getTitle()
        })
      }
    })

    view.webContents.on('page-title-updated', (_, title) => {
      if (!this.window.isDestroyed()) {
        this.window.webContents.send('tab-update', id, { title })
      }
    })

    view.webContents.on('did-navigate', (_, url) => {
      if (!this.window.isDestroyed()) {
        this.window.webContents.send('tab-update', id, { url })
      }
    })

    view.webContents.setWindowOpenHandler((details) => {
      if (!isHttpUrl(details.url)) {
        return { action: 'allow' }
      }
      const newId = this.createTab(details.url, true)
      if (!this.window.isDestroyed()) {
        this.window.webContents.send('tab-created', { id: newId, url: details.url, title: 'Loading...' })
      }
      return { action: 'deny' }
    })

    try {
      view.webContents.loadURL(url)
    } catch (e) {
      console.error('Failed to load URL:', url, e)
    }

    this.tabs.set(id, { id, url, title: 'Loading...', view })

    if (active) {
      this.switchTab(id)
    }

    return id
  }

  switchTab(id: string) {
    const tab = this.tabs.get(id)
    if (!tab) return

    if (this.activeTabId) {
      const currentTab = this.tabs.get(this.activeTabId)
      if (currentTab) {
        this.window.contentView.removeChildView(currentTab.view)
      }
    }

    this.window.contentView.addChildView(tab.view)
    tab.view.setBounds(this.bounds)

    this.activeTabId = id
  }

  closeTab(id: string) {
    const tab = this.tabs.get(id)
    if (!tab) return

    if (this.activeTabId === id) {
      this.window.contentView.removeChildView(tab.view)
      this.activeTabId = null
    } else {
      this.window.contentView.removeChildView(tab.view)
    }

    tab.view.webContents.close()
    this.tabs.delete(id)
  }

  setBounds(bounds: Electron.Rectangle) {
    this.bounds = bounds
    if (this.activeTabId) {
      const tab = this.tabs.get(this.activeTabId)
      if (tab) {
        tab.view.setBounds(bounds)
      }
    }
  }

  goBack() {
    if (this.activeTabId) this.tabs.get(this.activeTabId)?.view.webContents.navigationHistory.goBack()
  }

  goForward() {
    if (this.activeTabId) this.tabs.get(this.activeTabId)?.view.webContents.navigationHistory.goForward()
  }

  reload() {
    if (this.activeTabId) this.tabs.get(this.activeTabId)?.view.webContents.reload()
  }

  loadURL(id: string, url: string) {
    const tab = this.tabs.get(id)
    if (tab) {
      tab.view.webContents.loadURL(url)
    }
  }

  getTabSnapshotsForRenderer(): Array<{ id: string; url: string; title: string }> {
    return Array.from(this.tabs.values()).map((t) => ({
      id: t.id,
      url: t.view.webContents.getURL(),
      title: t.view.webContents.getTitle() || t.title || 'Loading...'
    }))
  }

  destroy() {
    this.tabs.forEach(tab => {
      try {
        this.window.contentView.removeChildView(tab.view)
        tab.view.webContents.close()
      } catch (e) { /* already destroyed */ }
    })
    this.tabs.clear()
  }
}

function getResourcePath(fileName: string): string {
  if (app.isPackaged) {
    return join(process.resourcesPath, fileName)
  }
  return join(__dirname, '../../resources', fileName)
}

// 获取图标路径的函数 - Windows 优先使用 ICO 文件
function getIconPath(): string {
  if (process.platform === 'win32') {
    // Windows 优先使用包含多尺寸的 ICO 文件
    const icoPath = getResourcePath('icon.ico')
    if (existsSync(icoPath)) {
      return icoPath
    }
  }
  // 其他平台或 Windows 没有 ICO 时使用 PNG
  return getResourcePath('logo.png')
}

function getTotalUnreadCount(): number {
  if (appUnreadTotalFromApi !== null) {
    return appUnreadTotalFromApi
  }
  let total = 0
  for (const info of unreadMap.values()) {
    total += info.count
  }
  return total
}

function updateTrayMenu(): void {
  if (!tray) return
  const totalUnread = getTotalUnreadCount()
  const contextMenu = Menu.buildFromTemplate([
    { label: totalUnread > 0 ? `未读消息 (${totalUnread})` : '无未读消息', enabled: false },
    { type: 'separator' },
    { label: '显示主界面', click: () => mainWindow?.show() },
    { label: '退出', click: () => { isQuitting = true; app.quit() } }
  ])
  tray.setContextMenu(contextMenu)
  tray.setToolTip('韫珠IM')
}

// --- 托盘悬浮弹窗 ---

function getTrayPopupHTML(): string {
  return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{font-family:'Microsoft YaHei','PingFang SC',sans-serif;background:transparent;overflow:hidden;user-select:none;}
.popup{background:#fff;border-radius:8px;box-shadow:0 4px 24px rgba(0,0,0,0.18);overflow:hidden;display:flex;flex-direction:column;max-height:100vh;}
.list{overflow-y:auto;max-height:calc(100vh - 40px);flex:1;}
.list::-webkit-scrollbar{width:4px;}
.list::-webkit-scrollbar-thumb{background:#ccc;border-radius:2px;}
.msg-item{display:flex;align-items:center;padding:10px 14px;cursor:pointer;border-bottom:1px solid #f0f0f0;transition:background 0.15s;}
.msg-item:last-child{border-bottom:none;}
.msg-item:hover{background:#f5f5f5;}
.msg-avatar-wrap{position:relative;width:40px;height:40px;flex-shrink:0;}
.badge{position:absolute;top:-5px;right:-5px;background:#ff3b30;color:#fff;border-radius:10px;padding:0 5px;font-size:10px;min-width:16px;height:16px;line-height:16px;text-align:center;font-weight:normal;z-index:1;}
.msg-info{margin-left:10px;overflow:hidden;flex:1;}
.msg-name{font-size:14px;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:500;}
.msg-content{font-size:12px;color:#999;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:3px;}
.footer{text-align:center;padding:10px;color:#576b95;font-size:13px;cursor:pointer;border-top:1px solid #eee;flex-shrink:0;transition:background 0.15s;}
.footer:hover{background:#f5f5f5;}
.empty{padding:20px;text-align:center;color:#999;font-size:13px;}
</style>
</head>
<body>
<div class="popup">
  <div class="list" id="list"></div>
  <div class="footer" id="dismiss">暂不处理</div>
</div>
<script>
(function(){
  const list = document.getElementById('list');
  const dismiss = document.getElementById('dismiss');
  const ipc = window.electron && window.electron.ipcRenderer;

  var GRADIENT_PAIRS = [
    ['#1e3a8a','#93c5fd'],['#166534','#86efac'],['#c2410c','#fdba74'],['#b91c1c','#fca5a5'],['#5b21b6','#c4b5fd'],
    ['#0f766e','#5eead4'],['#3730a3','#a5b4fc'],['#0d9488','#2dd4bf'],['#b45309','#fcd34d'],['#be123c','#fda4af'],
    ['#0369a1','#7dd3fc'],['#4d7c0f','#bef264'],['#86198f','#e879f9'],['#db2777','#fbcfe8'],['#047857','#6ee7b7'],
    ['#6d28d9','#ddd6fe'],['#1e40af','#93c5fd'],['#ea580c','#fed7aa'],['#0e7490','#99f6e4'],['#881337','#fbcfe8']
  ];
  function getAvatarText(name){
    var n = String(name || '').trim();
    if(!n) return '?';
    var cjk = (n.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) || []).length;
    var letterCount = n.replace(/\\s/g,'').length;
    var isCJK = letterCount > 0 && cjk >= letterCount / 2;
    if(isCJK){
      if(n.length <= 2) return n;
      return n.slice(-2);
    }
    var words = n.split(/\\s+/).filter(Boolean);
    if(words.length >= 2){
      var a = (words[0][0] || '').toUpperCase();
      var b = (words[1][0] || '').toUpperCase();
      return (a + b) || '?';
    }
    if(words.length === 1 && words[0].length >= 2) return words[0].slice(0,2).toUpperCase();
    if(words.length === 1 && words[0].length === 1) return words[0].toUpperCase();
    return '?';
  }
  function getGradientIndex(id, name){
    var s = String(id || '').trim() || String(name || '').trim();
    var hash = 0;
    for(var i = 0; i < s.length; i++){
      hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
    }
    return Math.abs(hash) % GRADIENT_PAIRS.length;
  }
  function getApplicationGradientIndex(name){
    var s = String(name || '').trim() || 'SYSTEM';
    var hash = 0;
    for(var i = 0; i < s.length; i++){
      hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
    }
    return Math.abs(hash) % GRADIENT_PAIRS.length;
  }
  function avatarBlockHtml(item){
    var displayName = item.name || '';
    var text = getAvatarText(displayName);
    var idx = item.id < 0 ? getApplicationGradientIndex(displayName) : getGradientIndex(item.id, displayName);
    var pair = GRADIENT_PAIRS[idx];
    var c1 = pair[0], c2 = pair[1];
    var style = 'width:40px;height:40px;border-radius:50%;overflow:hidden;background-color:'+c1+
      ';background-image:linear-gradient(135deg,'+c1+','+c2+');display:flex;align-items:center;justify-content:center;'+
      'color:#fff;font-size:16px;font-weight:500;line-height:1;white-space:nowrap;font-family:\\'PingFang SC\\',Roboto,-apple-system,sans-serif;box-sizing:border-box;';
    var badgeText = item.count > 99 ? '99+' : String(item.count);
    return '<div class="msg-avatar-wrap">'+
      '<div style="'+style+'">'+escapeHtml(text)+'</div>'+
      '<div class="badge">'+escapeHtml(badgeText)+'</div>'+
      '</div>';
  }

  if(ipc){
    ipc.on('update-unread', function(_, items){
      list.innerHTML = '';
      if(!items || items.length === 0){
        list.innerHTML = '<div class="empty">暂无未读消息</div>';
        return;
      }
      items.forEach(function(item){
        var div = document.createElement('div');
        div.className = 'msg-item';
        div.innerHTML =
          avatarBlockHtml(item) +
          '<div class="msg-info">' +
            '<div class="msg-name">' + escapeHtml(item.name) + '</div>' +
            '<div class="msg-content">' + escapeHtml(item.content) + '</div>' +
          '</div>';
        div.addEventListener('click', function(){ ipc.send('tray-popup-click', item.id); });
        list.appendChild(div);
      });
    });
  }

  dismiss.addEventListener('click', function(){
    if(ipc) ipc.send('tray-popup-dismiss');
  });

  document.addEventListener('mouseleave', function(){
    if(ipc) ipc.send('tray-popup-mouse-leave');
  });

  document.addEventListener('mouseenter', function(){
    if(ipc) ipc.send('tray-popup-mouse-enter');
  });

  function escapeHtml(str){
    if(!str) return '';
    return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
  }
})();
</script>
</body>
</html>`
}

function createTrayPopup(): void {
  if (trayPopupWindow && !trayPopupWindow.isDestroyed()) return

  trayPopupWindow = new BrowserWindow({
    width: 320,
    height: 200,
    frame: false,
    transparent: true,
    alwaysOnTop: true,
    skipTaskbar: true,
    resizable: false,
    show: false,
    focusable: false,
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      nodeIntegration: false,
      contextIsolation: true,
    }
  })

  trayPopupWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(getTrayPopupHTML())}`)

  trayPopupWindow.on('closed', () => {
    trayPopupWindow = null
  })
}

function getUnreadListForPopup(): { id: number, name: string, content: string, count: number }[] {
  const list: { id: number, name: string, content: string, count: number }[] = []
  for (const [id, info] of unreadMap.entries()) {
    list.push({ id, name: info.name, content: info.content, count: info.count })
  }
  return list
}

function showTrayPopup(): void {
  if (!tray || unreadMap.size === 0) return

  if (!trayPopupWindow || trayPopupWindow.isDestroyed()) {
    createTrayPopup()
  }
  if (!trayPopupWindow) return

  if (trayPopupHideTimer) {
    clearTimeout(trayPopupHideTimer)
    trayPopupHideTimer = null
  }

  if (trayPopupWindow.isVisible()) {
    trayPopupWindow.webContents.send('update-unread', getUnreadListForPopup())
    return
  }

  const trayBounds = tray.getBounds()
  const itemHeight = 61
  const footerHeight = 40
  const maxItems = 5
  const visibleItems = Math.min(unreadMap.size, maxItems)
  const popupHeight = visibleItems * itemHeight + footerHeight + 2
  const popupWidth = 320

  const display = screen.getDisplayNearestPoint({ x: trayBounds.x, y: trayBounds.y })
  const workArea = display.workArea

  let x = Math.round(trayBounds.x - popupWidth / 2 + trayBounds.width / 2)
  let y: number

  if (trayBounds.y < workArea.y + workArea.height / 2) {
    y = trayBounds.y + trayBounds.height + 4
  } else {
    y = trayBounds.y - popupHeight - 4
  }

  if (x + popupWidth > workArea.x + workArea.width) {
    x = workArea.x + workArea.width - popupWidth - 4
  }
  if (x < workArea.x) {
    x = workArea.x + 4
  }

  trayPopupWindow.setSize(popupWidth, popupHeight)
  trayPopupWindow.setPosition(x, y)

  trayPopupWindow.webContents.once('did-finish-load', () => {
    if (trayPopupWindow && !trayPopupWindow.isDestroyed()) {
      trayPopupWindow.webContents.send('update-unread', getUnreadListForPopup())
    }
  })

  if (trayPopupWindow.webContents.isLoading()) {
    // will send data in did-finish-load
  } else {
    trayPopupWindow.webContents.send('update-unread', getUnreadListForPopup())
  }

  trayPopupWindow.showInactive()
}

function hideTrayPopup(): void {
  if (trayPopupHideTimer) {
    clearTimeout(trayPopupHideTimer)
    trayPopupHideTimer = null
  }
  if (trayHoverCheckTimer) {
    clearInterval(trayHoverCheckTimer)
    trayHoverCheckTimer = null
  }
  if (trayPopupWindow && !trayPopupWindow.isDestroyed() && trayPopupWindow.isVisible()) {
    trayPopupWindow.hide()
  }
}

function scheduleTrayPopupHide(): void {
  if (trayPopupHideTimer) clearTimeout(trayPopupHideTimer)
  trayPopupHideTimer = setTimeout(() => {
    hideTrayPopup()
  }, 300)
}

function cancelTrayPopupHide(): void {
  if (trayPopupHideTimer) {
    clearTimeout(trayPopupHideTimer)
    trayPopupHideTimer = null
  }
}

function updateWindowTitle(): void {
  if (!mainWindow) return
  const totalUnread = getTotalUnreadCount()
  if (totalUnread > 0) {
    mainWindow.setTitle(`韫珠IM (${totalUnread} 条未读消息)`)
  } else {
    mainWindow.setTitle('韫珠IM')
  }
}

function updateTaskbarOverlay(): void {
  const totalUnread = getTotalUnreadCount()
  if (totalUnread > 0) {
    app.setBadgeCount(totalUnread)
  } else {
    app.setBadgeCount(0)
  }
}

function updateUnreadStatus(): void {
  updateTrayMenu()
  updateWindowTitle()
  updateTaskbarOverlay()
  if (unreadMap.size > 0) {
    startBlinking()
  } else {
    stopBlinking()
    hideTrayPopup()
  }
  if (trayPopupWindow && !trayPopupWindow.isDestroyed() && trayPopupWindow.isVisible()) {
    trayPopupWindow.webContents.send('update-unread', getUnreadListForPopup())
  }
}

function startBlinking(): void {
  if (blinkInterval) return
  let isEmpty = false
  const iconPath = getIconPath()
  const emptyIcon = nativeImage.createEmpty()
  const normalIcon = nativeImage.createFromPath(iconPath)
  
  blinkInterval = setInterval(() => {
    if (!tray) return
    if (isEmpty) {
      tray.setImage(normalIcon)
    } else {
      tray.setImage(emptyIcon)
    }
    isEmpty = !isEmpty
  }, 500)
}

function stopBlinking(): void {
  if (blinkInterval) {
    clearInterval(blinkInterval)
    blinkInterval = null
  }
  if (tray) {
    const iconPath = getIconPath()
    tray.setImage(nativeImage.createFromPath(iconPath))
  }
}

function createWindow(): void {
  // Create the browser window.
  const iconPath = getIconPath()
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 700,
    show: false,
    resizable: true, // 与手动登录后一致，否则 Windows 标题栏不显示最大化；登录成功仍会 setSize/center
    title: '韫珠IM',
    icon: iconPath,
    autoHideMenuBar: true,
    titleBarStyle: 'hidden', // Hide title bar
    titleBarOverlay: {
      color: '#ffffff', // Match login background
      symbolColor: '#747474', // Match control color
      height: 30
    },
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      nodeIntegration: false,
      contextIsolation: true,
      webSecurity: true
    }
  })

  mainWindow.on('ready-to-show', () => {
    mainWindow?.show()
  })

  mainWindow.on('close', (event) => {
    if (!isQuitting) {
      event.preventDefault()
      mainWindow?.hide()
      return false
    }
    return true
  })
  
  mainWindow.on('focus', () => {
    stopBlinking()
    // 主界面显示时清除任务栏徽章
    app.setBadgeCount(0)
  })

  mainWindow.on('show', () => {
    // 主界面显示时清除任务栏徽章
    app.setBadgeCount(0)
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    // Intercept target="_blank" and open custom browser window
    if (isHttpUrl(details.url)) {
      createInternalBrowserWindow(details.url)
      return { action: 'deny' }
    }
    return { action: 'allow' }
  })

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }
}

let browserWindow: BrowserWindow | null = null
let viewManager: ViewManager | null = null
/** 新建内置浏览器窗口时，首标签在渲染进程就绪后再同步，避免 tab-created 早于 listener */
let pendingBrowserInitialUrl: string | null = null

function flushPendingBrowserInitialTab(): void {
  if (!pendingBrowserInitialUrl || !viewManager || !browserWindow || browserWindow.isDestroyed()) return
  const url = pendingBrowserInitialUrl
  pendingBrowserInitialUrl = null
  viewManager.createTab(url, true)
}

function syncBrowserTabsToRenderer(): void {
  if (!viewManager || !browserWindow || browserWindow.isDestroyed()) return
  const snapshots = viewManager.getTabSnapshotsForRenderer()
  if (snapshots.length === 0) return
  browserWindow.webContents.send('browser-tabs-sync', snapshots)
}

// Function to create the custom browser window
function createInternalBrowserWindow(targetUrl: string): void {
  if (browserWindow && !browserWindow.isDestroyed()) {
    if (browserWindow.isMinimized()) browserWindow.restore()
    browserWindow.show()
    browserWindow.focus()
    
    // 如果窗口已存在，且管理器存在，则新建标签
    if (viewManager) {
        const id = viewManager.createTab(targetUrl, true)
        browserWindow.webContents.send('tab-created', { id, url: targetUrl, title: 'Loading...' })
    }
    return
  }

  const iconPath = getIconPath()
  browserWindow = new BrowserWindow({
    width: 1024,
    height: 768,
    title: '应用中心', // Built-in Browser
    icon: iconPath,
    autoHideMenuBar: true, // Show menu bar for navigation
    titleBarStyle: 'hidden',
    titleBarOverlay: {
      color: '#e2e2e2',
      symbolColor: '#333',
      height: 38
    },
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      nodeIntegration: false,
      contextIsolation: true
    }
  })

  browserWindow.maximize()

  viewManager = new ViewManager(browserWindow)
  pendingBrowserInitialUrl = targetUrl

  // Load the browser route with initial URL
  // We use hash parameter to avoid Vite dev server 403 error with query params on root
  const hash = `browser` // No url param here, we load it via ViewManager
  
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    browserWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}#${hash}`)
  } else {
    browserWindow.loadFile(join(__dirname, '../renderer/index.html'), { hash: hash })
  }

  browserWindow.on('closed', () => {
    pendingBrowserInitialUrl = null
    viewManager?.destroy()
    viewManager = null
    browserWindow = null
  })

  browserWindow.webContents.once('did-finish-load', () => {
    browserWindow?.setTitle('应用中心')
    // 渲染进程未就绪时的兜底：稍后再创建首标签并同步 UI
    setTimeout(() => {
      flushPendingBrowserInitialTab()
      syncBrowserTabsToRenderer()
    }, 400)
  })
}

// 统一处理来自渲染进程的 Browser Action
ipcMain.on('browser-action', (event, action) => {
    if (!viewManager || !browserWindow || browserWindow.isDestroyed()) return
    // 简单的鉴权：只允许 browserWindow 发送控制指令
    if (event.sender.id !== browserWindow.webContents.id) return

    switch (action.type) {
      case 'browser-ui-ready':
        flushPendingBrowserInitialTab()
        syncBrowserTabsToRenderer()
        break
      case 'create-tab':
        const id = viewManager.createTab(action.url || 'about:blank', true)
        event.reply('tab-created', { id, url: action.url, title: 'Loading...' })
        break
      case 'switch-tab':
        viewManager.switchTab(action.id)
        break
      case 'close-tab':
        viewManager.closeTab(action.id)
        break
      case 'go-back':
        viewManager.goBack()
        break
      case 'go-forward':
        viewManager.goForward()
        break
      case 'reload':
        viewManager.reload()
        break
      case 'load-url':
        viewManager.loadURL(action.id, action.url)
        break
      case 'resize-view':
        if (action.bounds) {
            viewManager.setBounds(action.bounds)
        }
        break
    }
})

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  app.quit()
} else {

app.on('second-instance', () => {
  if (mainWindow) {
    if (mainWindow.isMinimized()) mainWindow.restore()
    if (!mainWindow.isVisible()) mainWindow.show()
    mainWindow.focus()
  }
})

app.whenReady().then(() => {
  electronApp.setAppUserModelId('com.hnyunzhu.im')
  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })

  ipcMain.on('ping', () => console.log('pong'))

  ipcMain.handle('get-app-version', () => app.getVersion())

  // 生产环境自动更新（自建服务器）
  if (!is.dev) {
    autoUpdater.checkForUpdatesAndNotify()
    autoUpdater.on('update-available', (info) => {
      mainWindow?.webContents.send('update-available', info)
    })
    autoUpdater.on('update-downloaded', () => {
      mainWindow?.webContents.send('update-downloaded')
    })
    autoUpdater.on('download-progress', (info: { percent: number; transferred: number; total: number; bytesPerSecond: number }) => {
      mainWindow?.webContents.send('update-download-progress', {
        percent: info.percent,
        transferred: info.transferred,
        total: info.total,
        bytesPerSecond: info.bytesPerSecond
      })
    })
    autoUpdater.on('update-not-available', () => {
      mainWindow?.webContents.send('update-not-available')
    })
    autoUpdater.on('error', (err) => {
      mainWindow?.webContents.send('update-error', err.message)
    })
    // 运行时每 5 小时自动检测一次更新
    const FIVE_HOURS_MS = 5 * 60 * 60 * 1000
    setInterval(() => {
      autoUpdater.checkForUpdates()
    }, FIVE_HOURS_MS)
  }
  ipcMain.on('check-for-updates', () => {
    if (!is.dev) autoUpdater.checkForUpdates()
  })
  ipcMain.on('quit-and-install', () => {
    autoUpdater.quitAndInstall(false, true)
  })

  ipcMain.on('sync-unread-total', (_, total: number) => {
    appUnreadTotalFromApi = typeof total === 'number' && !Number.isNaN(total) ? Math.max(0, Math.floor(total)) : 0
    updateUnreadStatus()
  })

  ipcMain.on('login-success', () => {
    // 登录成功后清空消息中心未读，避免切换账号展示上个账号的残留
    unreadMap.clear()
    appUnreadTotalFromApi = null
    updateUnreadStatus()
    if (mainWindow) {
      mainWindow.setSize(1000, 700)
      mainWindow.setResizable(true)
      mainWindow.center()
      mainWindow.setTitleBarOverlay({
        color: '#f5f5f5',
        symbolColor: '#747474',
        height: 30
      })
    }
  })

  ipcMain.on('start-notification', (_, data: { id: number, name: string, content: string }) => {
    const { id, name, content } = data
    const existing = unreadMap.get(id)
    unreadMap.set(id, {
      name,
      content,
      count: existing ? existing.count + 1 : 1
    })
    updateUnreadStatus()
  })

  // 清除未读消息
  ipcMain.on('clear-unread', (_, contactId: number) => {
    if (unreadMap.has(contactId)) {
      unreadMap.delete(contactId)
      updateUnreadStatus()
    }
  })

  // 清除所有未读消息
  ipcMain.on('clear-all-unread', () => {
    unreadMap.clear()
    appUnreadTotalFromApi = null
    updateUnreadStatus()
  })

  // 处理打开 URL 请求（用于通知消息的 SSO 跳转）
  ipcMain.on('open-url', (_, url: string) => {
    if (url && (url.startsWith('http://') || url.startsWith('https://'))) {
      // 使用内部浏览器窗口打开
      if (viewManager) {
        viewManager.createTab(url, true)
      } else {
        // 如果浏览器窗口未初始化，使用系统默认浏览器
        shell.openExternal(url)
      }
    }
  })

  // 使用系统默认浏览器打开 URL（应用中心「用系统浏览器打开」选项）
  ipcMain.on('open-url-external', (_, url: string) => {
    if (url && (url.startsWith('http://') || url.startsWith('https://'))) {
      shell.openExternal(url)
    }
  })

  // 图片/视频：下载到临时目录后用系统默认应用打开（不再使用内嵌预览窗口）
  ipcMain.on('open-image-preview', (_, imageUrl: string) => {
    void downloadMediaToTempAndOpen(imageUrl, 'image.png').catch((e) => {
      console.error(e)
      dialog.showErrorBox('打开失败', e instanceof Error ? e.message : String(e))
    })
  })

  ipcMain.on('open-video-player', (_, videoUrl: string, videoTitle?: string) => {
    void downloadMediaToTempAndOpen(videoUrl, videoTitle || 'video.mp4').catch((e) => {
      console.error(e)
      dialog.showErrorBox('打开失败', e instanceof Error ? e.message : String(e))
    })
  })

  // Create tray
  const iconPath = getIconPath()
  const trayIcon = nativeImage.createFromPath(iconPath)
  
  // Windows 托盘图标设置
  if (process.platform === 'win32') {
    // 确保图标不是模板模式，这样图标会正常显示
    trayIcon.setTemplateImage(false)
  }
  
  tray = new Tray(trayIcon)
  tray.setToolTip('韫珠IM')
  tray.on('click', () => {
    hideTrayPopup()
    mainWindow?.show()
  })
  tray.on('mouse-move', () => {
    if (unreadMap.size > 0) {
      showTrayPopup()
      cancelTrayPopupHide()

      if (!trayHoverCheckTimer) {
        trayHoverCheckTimer = setInterval(() => {
          if (!tray) return
          const cursor = screen.getCursorScreenPoint()
          const tb = tray.getBounds()
          const isOverTray = cursor.x >= tb.x && cursor.x <= tb.x + tb.width &&
                            cursor.y >= tb.y && cursor.y <= tb.y + tb.height

          let isOverPopup = false
          if (trayPopupWindow && !trayPopupWindow.isDestroyed() && trayPopupWindow.isVisible()) {
            const pb = trayPopupWindow.getBounds()
            isOverPopup = cursor.x >= pb.x && cursor.x <= pb.x + pb.width &&
                         cursor.y >= pb.y && cursor.y <= pb.y + pb.height
          }

          if (!isOverTray && !isOverPopup) {
            hideTrayPopup()
          }
        }, 300)
      }
    }
  })
  updateTrayMenu()

  ipcMain.on('tray-popup-click', (_, contactId: number) => {
    hideTrayPopup()
    if (mainWindow) {
      mainWindow.show()
      mainWindow.focus()
      mainWindow.webContents.send('switch-contact', contactId)
    }
  })

  ipcMain.on('tray-popup-dismiss', () => {
    // 「暂不处理」：清空主进程托盘未读 Map，停止闪烁；不改动 appUnreadTotalFromApi，避免干扰主界面 API 未读总数
    unreadMap.clear()
    updateUnreadStatus()
  })

  ipcMain.on('tray-popup-mouse-leave', () => {
    scheduleTrayPopupHide()
  })

  ipcMain.on('tray-popup-mouse-enter', () => {
    cancelTrayPopupHide()
  })

  createWindow()

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

} // end of gotTheLock else
