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
}

/** 渲染层同步过来的页面（用于屏幕窗口按键切换） */
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>()
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
}
const carousels = new Map<number, CarouselState>()

/**
 * 统一的屏幕键盘处理：
 * - Esc 立即退出 / F5 立即刷新
 * - 锁定键切换全局快捷键识别（避免网页交互输入数字误触切屏）
 * - 数字键、方向键需要"长按超过阈值"才触发，快速输入不影响网页操作
 */
interface KeyBindings {
  onEscape: () => void
  onF5: () => void
  onPrev: () => void
  onNext: () => void
  onNumber: (n: number) => void
  onLockToggle: (locked: boolean) => void
}

function makeKeyHandler(b: KeyBindings): (event: Electron.Event, input: Electron.Input) => void {
  let hold = ''
  let holdT = 0
  return (event, input) => {
    const s = getSettings()
    const threshold = 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
      }
      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()) 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)
}

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.pages.length} 页 · 第 ${car.current + 1} 页）`,
        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
    }
  })
}

function ensureWindow(index: number, display: Electron.Display): BrowserWindow {
  let win = screenWindows.get(index)
  if (win && !win.isDestroyed()) 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' }))

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

  // 屏幕窗口键盘：Esc 退出发布，F5 刷新，数字/方向键需长按超阈值，锁定键 F9 切换识别
  win.webContents.on(
    'before-input-event',
    makeKeyHandler({
      onEscape: () => closeScreen(index),
      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)
    })
  )

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

  screenWindows.set(index, win)
  return win
}

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

  const win = ensureWindow(index, display)
  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): 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: pi === 0,
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
        sandbox: false,
        spellcheck: false
      }
    })
    win.setMenuBarVisibility(false)
    win.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
    win.setTitle(page.title)
    void win.loadURL(page.url)

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

    // 键盘：在可见窗体上捕获，方向/数字键需长按超阈值
    win.webContents.on(
      'before-input-event',
      makeKeyHandler({
        onEscape: () => stopCarousel(index),
        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)
      })
    )

    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 }
  if (intervalSec > 0 && pages.length > 1) {
    state.timer = setInterval(() => {
      const st = carousels.get(index)
      if (st) switchCarousel(index, st.current + 1)
    }, intervalSec * 1000)
  }
  carousels.set(index, state)
  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
  state.current = ((next % n) + n) % n
  state.wins.forEach((w, i) => {
    if (w.isDestroyed()) return
    if (i === state.current) {
      w.show()
      w.setFullScreen(true)
      w.focus()
    } else {
      w.hide()
    }
  })
  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 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: () => restoreMain(),
        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)
      })
    )
    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 = []
}
