import { BrowserWindow, screen, WebContentsView } from 'electron'
import { getSettings } from './settings'

export interface PlayingInfo {
  title: string
  url: string
}

export interface ScreenInfo {
  index: number
  name: string
  res: string
  pos: string
  primary: boolean
  playing: PlayingInfo | null
  /** 单屏轮播是否处于自动切换中（「停止轮播」按钮据此启用） */
  carouselAuto?: boolean
}

/** 渲染层同步过来的页面（用于屏幕窗口按键切换） */
export interface SyncPage {
  id: string
  title: string
  url: string
  screen: number
  ctrl: number
  display: boolean
}

export interface CarouselPage {
  url: string
  title: string
}

const screenWindows = new Map<number, BrowserWindow>()
/** 多屏发布模式的窗口集合：仅保留 Esc/F5，禁用数字/方向/锁定键 */
const navDisabledWins = new Set<BrowserWindow>()
let lastPages: SyncPage[] = []
let broadcastFn: ((list: ScreenInfo[]) => void) | null = null

/** 全局快捷键识别锁定（遥控设置界面可切换） */
let keyLocked = false
export function setKeyLock(v: boolean): void {
  keyLocked = v
}
export function isKeyLocked(): boolean {
  return keyLocked
}

/** 单屏轮播状态：屏幕索引 → 该屏叠放的页面窗体列表 */
interface CarouselState {
  screenIndex: number
  wins: BrowserWindow[]
  pages: CarouselPage[]
  current: number
  timer: NodeJS.Timeout | null
  /** 是否自动轮播（有定时器在跑） */
  auto: boolean
  /** 状态显示名（单屏轮播 / 交互发布） */
  label: string
}
const carousels = new Map<number, CarouselState>()

/**
 * 统一的屏幕键盘处理：
 * - Esc 立即退出 / F5 立即刷新
 * - 锁定键切换全局快捷键识别（避免网页交互输入数字误触切屏）
 * - 数字键、方向键默认需要"长按超过阈值"才触发，避免网页交互输入误触；
 *   quick 模式下（大屏发布/轮播/主屏播放）阈值强制为 0，按键即时响应
 */
interface KeyBindings {
  onEscape: () => void
  onF5: () => void
  onPrev: () => void
  onNext: () => void
  onNumber: (n: number) => void
  onLockToggle: (locked: boolean) => void
  /** true 时禁用数字/方向/锁定键，仅保留 Esc/F5（多屏发布模式） */
  navDisabled?: () => boolean
}

function makeKeyHandler(b: KeyBindings, quick = false): (event: Electron.Event, input: Electron.Input) => void {
  let hold = ''
  let holdT = 0
  return (event, input) => {
    const s = getSettings()
    const threshold = quick ? 0 : Math.max(0, s.keyThreshold)
    const lockKey = (s.keyLockKey || 'F9').toLowerCase()
    if (input.type === 'keyDown') {
      if (input.key === 'Escape') {
        event.preventDefault()
        b.onEscape()
        return
      }
      if (input.key === 'F5') {
        event.preventDefault()
        b.onF5()
        return
      }
      // 多屏发布模式：仅保留 Esc/F5，其余按键一律忽略
      if (b.navDisabled?.() ?? false) return
      if (lockKey && input.key.toLowerCase() === lockKey) {
        event.preventDefault()
        const nv = !isKeyLocked()
        setKeyLock(nv)
        b.onLockToggle(nv)
        return
      }
      const isNav =
        input.key === 'ArrowUp' ||
        input.key === 'ArrowLeft' ||
        input.key === 'ArrowDown' ||
        input.key === 'ArrowRight'
      const n = parseInt(input.key)
      if (isNav || (!isNaN(n) && n >= 1 && n <= 9)) {
        // 仅在首次按下时记录时间戳；auto-repeat 不刷新，避免长按被持续重置
        if (hold !== input.key) {
          hold = input.key
          holdT = Date.now()
        }
      }
      return
    }
    if (input.type === 'keyUp' && input.key === hold) {
      hold = ''
      const dur = Date.now() - holdT
      if (dur < threshold || isKeyLocked() || (b.navDisabled?.() ?? false)) return
      event.preventDefault()
      if (input.key === 'ArrowUp' || input.key === 'ArrowLeft') {
        b.onPrev()
        return
      }
      if (input.key === 'ArrowDown' || input.key === 'ArrowRight') {
        b.onNext()
        return
      }
      const n = parseInt(input.key)
      if (!isNaN(n) && n >= 1 && n <= 9) b.onNumber(n)
    }
  }
}

function lockHint(win: BrowserWindow | null, locked: boolean): void {
  if (!win || win.isDestroyed()) return
  const key = getSettings().keyLockKey || 'F9'
  const prev = win.getTitle()
  win.setTitle(locked ? `🔒 快捷键已锁定（按 ${key} 解锁）` : `快捷键识别已开启（按 ${key} 锁定）`)
  setTimeout(() => {
    if (!win.isDestroyed()) win.setTitle(prev)
  }, 2000)
}

/** 在窗体页面左上角显示临时提示（2 秒后自动移除） */
function hintAt(win: BrowserWindow, text: string): void {
  if (!win || win.isDestroyed()) return
  const script = `(() => {
    const old = document.getElementById('__sb_hint_root')
    if (old) old.remove()
    const d = document.createElement('div')
    d.id = '__sb_hint_root'
    d.textContent = ${JSON.stringify(text)}
    d.style.cssText =
      'position:fixed;top:16px;left:16px;z-index:2147483647;padding:8px 16px;' +
      'border-radius:6px;background:rgba(0,0,0,.65);color:#fff;' +
      'font:14px/1.6 "Microsoft YaHei",sans-serif;pointer-events:none;' +
      'box-shadow:0 2px 8px rgba(0,0,0,.3);'
    document.documentElement.appendChild(d)
    setTimeout(() => d.remove(), 2000)
  })()`
  void win.webContents.executeJavaScript(script).catch(() => undefined)
}

export function setPages(pages: SyncPage[]): void {
  lastPages = pages
}

export function setBroadcast(fn: (list: ScreenInfo[]) => void): void {
  broadcastFn = fn
}

function emitChange(): void {
  broadcastFn?.(listScreens())
}

function sortedDisplays(): Electron.Display[] {
  const primary = screen.getPrimaryDisplay()
  return [...screen.getAllDisplays()].sort((a, b) => {
    const pa = a.id === primary.id ? 0 : 1
    const pb = b.id === primary.id ? 0 : 1
    if (pa !== pb) return pa - pb
    return a.bounds.x - b.bounds.x || a.bounds.y - b.bounds.y
  })
}

export function listScreens(): ScreenInfo[] {
  return sortedDisplays().map((d, i) => {
    const index = i + 1
    const win = screenWindows.get(index)
    const car = carousels.get(index)
    let playing: PlayingInfo | null = null
    if (car && car.wins.some((w) => !w.isDestroyed() && w.isVisible())) {
      playing = {
        title: `${car.label}（${car.pages.length} 页 · 第 ${car.current + 1} 页${car.auto ? ' · 自动' : ''}）`,
        url: car.pages[car.current]?.url ?? ''
      }
    } else if (win && !win.isDestroyed() && win.isVisible()) {
      playing = win.getTitle() ? { title: win.getTitle(), url: win.webContents.getURL() } : null
    }
    return {
      index,
      name: `屏幕 ${index}`,
      res: `${d.size.width}×${d.size.height}`,
      pos: d.id === screen.getPrimaryDisplay().id ? '主显示器' : '扩展显示器',
      primary: d.id === screen.getPrimaryDisplay().id,
      playing,
      carouselAuto: car ? car.auto : undefined
    }
  })
}

function ensureWindow(index: number, display: Electron.Display, opts?: { navDisabled?: boolean }): BrowserWindow {
  let win = screenWindows.get(index)
  if (win && !win.isDestroyed()) {
    // 复用窗口时也要刷新“仅 Esc/F5”标记（例如先预览本页再多屏发布，或反之）
    if (opts?.navDisabled) navDisabledWins.add(win)
    else navDisabledWins.delete(win)
    return win
  }

  win = new BrowserWindow({
    x: display.bounds.x,
    y: display.bounds.y,
    width: display.bounds.width,
    height: display.bounds.height,
    frame: false,
    autoHideMenuBar: true,
    backgroundColor: '#050b18',
    webPreferences: {
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: false,
      spellcheck: false
    }
  })

  win.setMenuBarVisibility(false)
  win.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))

  if (opts?.navDisabled) navDisabledWins.add(win)
  else navDisabledWins.delete(win)

  win.once('ready-to-show', () => {
    if (win && !win.isDestroyed()) {
      win.show()
      win.setFullScreen(true)
      win.focus()
    }
  })

  // 屏幕窗口键盘：Esc 关闭所有播放，F5 刷新，数字/方向键即时切换，锁定键 F9 切换识别
  win.webContents.on(
    'before-input-event',
    makeKeyHandler(
      {
        onEscape: () => closeAllScreens(),
        onF5: () => win?.webContents.reload(),
        onPrev: () => switchCarousel(index, (carousels.get(index)?.current ?? 0) - 1),
        onNext: () => switchCarousel(index, (carousels.get(index)?.current ?? 0) + 1),
        onNumber: (n) => {
          const page = lastPages.find((p) => p.ctrl === n)
          if (page) publishScreen(index, page.url, page.title)
        },
        onLockToggle: (lv) => lockHint(win, lv),
        navDisabled: () => (win ? navDisabledWins.has(win) : false)
      },
      true
    )
  )

  win.on('closed', () => {
    screenWindows.delete(index)
    if (win) navDisabledWins.delete(win)
    emitChange()
  })

  screenWindows.set(index, win)
  return win
}

export function publishScreen(
  index: number,
  url: string,
  title: string,
  opts?: { navDisabled?: boolean }
): ScreenInfo[] {
  const displays = sortedDisplays()
  const display = displays[index - 1]
  if (!display) return listScreens()

  const win = ensureWindow(index, display, opts)
  if (!win.isDestroyed()) {
    win.setBounds(display.bounds)
  }
  win.setTitle(title)
  win.loadURL(url)
  emitChange()
  return listScreens()
}

export function closeScreen(index: number): ScreenInfo[] {
  const win = screenWindows.get(index)
  if (win && !win.isDestroyed()) win.close()
  screenWindows.delete(index)
  emitChange()
  return listScreens()
}

export function closeAllScreens(): void {
  for (const [index, win] of screenWindows) {
    if (win && !win.isDestroyed()) win.destroy()
    screenWindows.delete(index)
  }
  closeAllCarousels()
  restoreMain()
  closeProbe()
  emitChange()
}

export function screenCount(): number {
  return sortedDisplays().length
}

// ===== 单屏轮播（多页面窗体叠放） =====

/**
 * 在指定屏幕启动单屏轮播：为每个页面创建一个全屏窗体叠放在目标屏幕上，
 * 通过键盘 上/下 键循环切换、数字键直达，Esc 退出发布，F5 刷新当前页。
 * intervalSec > 0 时自动定时切换。
 */
export function startCarousel(index: number, pages: CarouselPage[], intervalSec = 0, label = '单屏轮播'): ScreenInfo[] {
  const displays = sortedDisplays()
  const display = displays[index - 1]
  if (!display) return listScreens()
  if (!pages || pages.length === 0) return listScreens()

  stopCarousel(index)

  const b = display.bounds
  const wins: BrowserWindow[] = []

  pages.forEach((page, pi) => {
    const win = new BrowserWindow({
      x: b.x,
      y: b.y,
      width: b.width,
      height: b.height,
      frame: false,
      autoHideMenuBar: true,
      backgroundColor: '#050b18',
      show: false,
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
        sandbox: false,
        spellcheck: false
      }
    })
    win.setMenuBarVisibility(false)
    win.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
    win.setTitle(page.title)
    // 全部窗体预先设为全屏：避免首次切到时先从窗口化进入全屏，产生过渡动画/任务栏闪现
    win.setFullScreen(true)
    void win.loadURL(page.url)

    // 全部窗体就绪后保持显示并叠放：任一时刻最顶层都有全屏窗体覆盖任务栏，
    // 切换只改置顶顺序不做 hide/show，从根源避免任务栏闪现
    win.once('ready-to-show', () => {
      if (win.isDestroyed()) return
      win.show()
      if (!win.isFullScreen()) win.setFullScreen(true)
      const st = carousels.get(index)
      const first = st?.wins[0]
      if (first && !first.isDestroyed() && first !== win) {
        first.moveTop()
        first.focus()
      }
    })

    // 键盘：在可见窗体上捕获，方向/数字键即时切换（不要求长按）
    win.webContents.on(
      'before-input-event',
      makeKeyHandler(
        {
          onEscape: () => closeAllScreens(),
          onF5: () => {
            const state = carousels.get(index)
            state?.wins[state.current]?.webContents.reload()
          },
          onPrev: () => {
            const state = carousels.get(index)
            if (state) switchCarousel(index, state.current - 1)
          },
          onNext: () => {
            const state = carousels.get(index)
            if (state) switchCarousel(index, state.current + 1)
          },
          onNumber: (n) => {
            const state = carousels.get(index)
            if (state && n >= 1 && n <= state.wins.length) switchCarousel(index, n - 1)
          },
          onLockToggle: (lv) => lockHint(win, lv)
        },
        true
      )
    )

    win.on('closed', () => {
      if (carousels.has(index)) {
        carousels.delete(index)
        emitChange()
      }
    })

    wins.push(win)
  })

  const state: CarouselState = {
    screenIndex: index,
    wins,
    pages,
    current: 0,
    timer: null,
    auto: intervalSec > 0 && pages.length > 1,
    label
  }
  if (state.auto) {
    state.timer = setInterval(() => {
      const st = carousels.get(index)
      if (st) switchCarousel(index, st.current + 1)
    }, intervalSec * 1000)
  }
  carousels.set(index, state)
  emitChange()
  // 弹窗关闭后编辑器主窗口可能重新抢走焦点，延迟再次聚焦首个窗体
  setTimeout(() => {
    const st = carousels.get(index)
    const first = st?.wins[0]
    if (st && first && !first.isDestroyed()) {
      if (!first.isVisible()) first.show()
      if (!first.isFullScreen()) first.setFullScreen(true)
      first.moveTop()
      first.focus()
    }
  }, 400)
  return listScreens()
}

/**
 * 交互发布：指定 mainIndex 为交互主屏（大屏），其余屏幕按页面所属屏幕编号各自加载本屏页面。
 * 主屏轮播内容为全部屏幕的页面（按屏幕编号排序拼接），因此在主屏上按 ↑/↓ 或数字键，
 * 即可轮流把其他屏幕的页面切换到主屏上展示。
 */
export function startInteractive(req: { mainIndex: number; pagesByScreen: Record<number, CarouselPage[]> }): ScreenInfo[] {
  const displays = sortedDisplays()
  if (!displays[req.mainIndex - 1]) return listScreens()
  const indexes = Object.keys(req.pagesByScreen)
    .map(Number)
    .filter((i) => i >= 1 && i <= displays.length)
    .sort((a, b) => a - b)
  // 主屏轮播页面 = 所有屏幕页面（按屏幕编号排序）
  const mainPages: CarouselPage[] = []
  for (const i of indexes) mainPages.push(...req.pagesByScreen[i])
  for (const i of indexes) {
    const pages = i === req.mainIndex ? mainPages : req.pagesByScreen[i]
    if (pages.length > 0) startCarousel(i, pages, 0, i === req.mainIndex ? '交互发布' : '单屏轮播')
  }
  emitChange()
  return listScreens()
}

/** 切换到第 next 个窗体（不循环），越界时保持当前页并在左上角提示 */
function switchCarousel(index: number, next: number): void {
  const state = carousels.get(index)
  if (!state) return
  const n = state.wins.length
  if (n === 0) return
  // 取消循环播放：到第一屏/最后一屏时不再回绕，仅提示
  if (next < 0 || next >= n) {
    const w = state.wins[state.current]
    if (w && !w.isDestroyed()) hintAt(w, next < 0 ? '当前已经是第一屏' : '当前已经是最后一屏')
    // 自动轮播播到边界后停止定时切换，避免反复提示
    if (state.auto && state.timer) {
      clearInterval(state.timer)
      state.timer = null
      state.auto = false
    }
    return
  }
  state.current = next
  // 全屏窗体同尺寸完全叠放：切换只把目标窗体置顶并聚焦，不做 hide/show，
  // 使最顶层始终有全屏窗体覆盖任务栏，避免切页瞬间任务栏闪现
  state.wins.forEach((w, i) => {
    if (w.isDestroyed()) return
    if (i === state.current) {
      if (!w.isVisible()) w.show()
      if (!w.isFullScreen()) w.setFullScreen(true)
      w.moveTop()
      w.focus()
      // 切换后短暂延迟再聚焦一次，确保键盘输入落在当前窗体
      setTimeout(() => {
        if (!w.isDestroyed() && w.isVisible()) w.focus()
      }, 120)
    }
  })
  emitChange()
}

export function stopCarousel(index: number): ScreenInfo[] {
  const state = carousels.get(index)
  if (state) {
    if (state.timer) clearInterval(state.timer)
    for (const w of state.wins) {
      if (!w.isDestroyed()) w.destroy()
    }
    carousels.delete(index)
  }
  emitChange()
  return listScreens()
}

/** 停止自动轮播：仅清除定时切换，保留当前页面窗体显示（手动模式下「停止轮播」不可用） */
export function stopCarouselAuto(index: number): ScreenInfo[] {
  const state = carousels.get(index)
  if (state) {
    if (state.timer) {
      clearInterval(state.timer)
      state.timer = null
    }
    state.auto = false
  }
  emitChange()
  return listScreens()
}

export function closeAllCarousels(): void {
  for (const index of [...carousels.keys()]) {
    stopCarousel(index)
  }
}

// ===== 编辑器主窗口全屏播放（在当前编辑器屏幕也显示页面） =====

let mainWin: BrowserWindow | null = null
let mainView: WebContentsView | null = null
let mainPlayingIndex = -1

export function setMainWindow(win: BrowserWindow | null): void {
  mainWin = win
}

/** 主窗口当前所在屏幕编号（从 1 起） */
export function mainScreenIndex(): number {
  if (!mainWin || mainWin.isDestroyed()) return 1
  try {
    const display = screen.getDisplayMatching(mainWin.getContentBounds())
    const idx = sortedDisplays().findIndex((d) => d.id === display.id)
    return idx >= 0 ? idx + 1 : 1
  } catch {
    return 1
  }
}

/** 编辑器主窗口是否处于全屏播放中 */
export function isMainPlaying(): boolean {
  return mainView !== null && !!mainWin && !mainWin.isDestroyed()
}

/**
 * 在编辑器主窗口所在屏幕上全屏播放指定页面。
 * 使用 WebContentsView 覆盖在主窗口上方，退出时移除，不干扰编辑器运行状态。
 * 键盘：Esc 退出，F5 刷新，数字键 1-9 切换到对应 ControllerIndex 的页面。
 */
export function publishMain(url: string, title: string): ScreenInfo[] {
  if (!mainWin || mainWin.isDestroyed()) return listScreens()
  if (!mainView) {
    mainView = new WebContentsView({
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
        sandbox: false,
        spellcheck: false
      }
    })
    mainView.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
    mainView.webContents.on(
      'before-input-event',
      makeKeyHandler(
        {
          onEscape: () => closeAllScreens(),
          onF5: () => mainView?.webContents.reload(),
          onPrev: () => undefined,
          onNext: () => undefined,
          onNumber: (n) => {
            const page = lastPages.find((p) => p.ctrl === n)
            if (page) void publishMain(page.url, page.title)
          },
          onLockToggle: (lv) => lockHint(mainWin, lv)
        },
        true
      )
    )
    mainWin.contentView.addChildView(mainView)
  }
  const b = mainWin.getContentBounds()
  mainView.setBounds({ x: 0, y: 0, width: b.width, height: b.height })
  mainPlayingIndex = mainScreenIndex()
  mainWin.setTitle(title)
  void mainView.webContents.loadURL(url)
  mainView.webContents.focus()
  if (!mainWin.isFullScreen()) mainWin.setFullScreen(true)
  mainWin.show()
  emitChange()
  return listScreens()
}

/** 退出编辑器主窗口全屏播放，恢复编辑器界面 */
export function restoreMain(): ScreenInfo[] {
  const wasPlaying = mainView !== null
  mainPlayingIndex = -1
  if (mainWin && !mainWin.isDestroyed()) {
    mainWin.setFullScreen(false)
    if (wasPlaying) mainWin.setTitle('智慧农业大数据可视化控制中心')
  }
  if (mainView) {
    const v = mainView
    mainView = null
    try {
      mainWin?.contentView.removeChildView(v)
    } catch {
      /* 视图可能已销毁 */
    }
    if (!v.webContents.isDestroyed()) v.webContents.close()
  }
  if (wasPlaying) emitChange()
  return listScreens()
}

// ===== 检测屏幕（各屏显示编号 + 分辨率标签） =====

let probeWins: BrowserWindow[] = []
let probeTimer: NodeJS.Timeout | null = null

function probeHtml(label: string): string {
  return (
    '<!doctype html><html><head><meta charset="utf-8"></head><body style="margin:0;background:#000;overflow:hidden;font-family:Consolas,Microsoft YaHei,sans-serif;">' +
    '<div style="position:fixed;top:28px;left:32px;background:#000;border:3px solid #fff;border-radius:12px;padding:20px 30px;color:#fff;font-size:46px;font-weight:700;letter-spacing:2px;line-height:1.3;box-shadow:0 6px 30px rgba(0,0,0,.6);">' +
    label +
    '</div></body></html>'
  )
}

/**
 * 在每块屏幕上显示"屏幕编号 + 分辨率"标签（黑底白字、左上角醒目显示），
 * 6 秒后自动关闭，便于演示人员查看屏幕布局。
 */
export function probeScreens(): ScreenInfo[] {
  closeProbe()
  const displays = sortedDisplays()
  const primaryId = screen.getPrimaryDisplay().id
  for (let i = 0; i < displays.length; i++) {
    const d = displays[i]
    const label =
      `屏幕 ${i + 1}　${d.size.width} × ${d.size.height}` +
      (d.id === primaryId ? '<div style="font-size:26px;color:#ffd76a;margin-top:6px;">主显示器</div>' : '')
    const win = new BrowserWindow({
      x: d.bounds.x,
      y: d.bounds.y,
      width: d.bounds.width,
      height: d.bounds.height,
      frame: false,
      autoHideMenuBar: true,
      backgroundColor: '#000000',
      show: false,
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
        sandbox: false,
        spellcheck: false
      }
    })
    win.setMenuBarVisibility(false)
    win.once('ready-to-show', () => {
      if (!win.isDestroyed()) {
        win.setFullScreen(true)
        win.show()
        win.focus()
      }
    })
    void win.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(probeHtml(label))}`)
    probeWins.push(win)
  }
  probeTimer = setTimeout(closeProbe, 6000)
  return listScreens()
}

function closeProbe(): void {
  if (probeTimer) {
    clearTimeout(probeTimer)
    probeTimer = null
  }
  for (const w of probeWins) {
    if (!w.isDestroyed()) w.destroy()
  }
  probeWins = []
}
