import { useEffect, useRef, useState } from 'react'
import { useStore } from '../../store'
import { toast } from '../../toast'
import { detectScreens } from '../../publishActions'

interface KeyLog {
  key: string
  code: string
  t: string
}

const SCALE = [523, 587, 659, 698, 784, 880, 988, 1047] // C5 音阶

export default function DeviceTest(): React.JSX.Element {
  const screens = useStore((s) => s.screens)

  // ===== 键盘测试 =====
  const [keys, setKeys] = useState<KeyLog[]>([])
  const [kbdFocus, setKbdFocus] = useState(false)
  useEffect(() => {
    const h = (e: KeyboardEvent): void => {
      if (!kbdFocus) return
      setKeys((l) =>
        [{ key: e.key, code: e.code, t: new Date().toLocaleTimeString('zh-CN', { hour12: false }) }, ...l].slice(0, 10)
      )
      e.preventDefault()
    }
    window.addEventListener('keydown', h)
    return () => window.removeEventListener('keydown', h)
  }, [kbdFocus])

  // ===== 音箱测试 =====
  const [vol, setVol] = useState(0.5)
  const beep = (freq = 880, dur = 0.25): void => {
    try {
      const ctx = new AudioContext()
      const osc = ctx.createOscillator()
      const g = ctx.createGain()
      osc.type = 'sine'
      osc.frequency.value = freq
      g.gain.setValueAtTime(vol, ctx.currentTime)
      g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + dur)
      osc.connect(g).connect(ctx.destination)
      osc.start()
      osc.stop(ctx.currentTime + dur)
      void ctx.close().then(() => undefined)
    } catch {
      void window.api.beep()
    }
  }
  const playScale = (): void => {
    SCALE.forEach((f, i) => setTimeout(() => beep(f, 0.22), i * 220))
    toast('已播放 1234567i 音阶', 'ok')
  }

  // ===== 麦克风测试 =====
  const [micOn, setMicOn] = useState(false)
  const [level, setLevel] = useState(0)
  const micRef = useRef<{ stream: MediaStream; ctx: AudioContext; raf: number } | null>(null)
  useEffect(() => {
    return () => {
      const m = micRef.current
      if (m) {
        cancelAnimationFrame(m.raf)
        void m.ctx.close()
        m.stream.getTracks().forEach((t) => t.stop())
        micRef.current = null
      }
    }
  }, [])
  const toggleMic = async (): Promise<void> => {
    if (micOn) {
      const m = micRef.current
      if (m) {
        cancelAnimationFrame(m.raf)
        void m.ctx.close()
        m.stream.getTracks().forEach((t) => t.stop())
        micRef.current = null
      }
      setMicOn(false)
      setLevel(0)
      return
    }
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      const ctx = new AudioContext()
      const src = ctx.createMediaStreamSource(stream)
      const ana = ctx.createAnalyser()
      ana.fftSize = 512
      src.connect(ana)
      const data = new Uint8Array(ana.fftSize)
      const loop = (): void => {
        ana.getByteTimeDomainData(data)
        let sum = 0
        for (let i = 0; i < data.length; i++) {
          const v = (data[i] - 128) / 128
          sum += v * v
        }
        setLevel(Math.min(100, Math.round(Math.sqrt(sum / data.length) * 220)))
        micRef.current!.raf = requestAnimationFrame(loop)
      }
      loop()
      micRef.current = { stream, ctx, raf: 0 }
      setMicOn(true)
      toast('麦克风已开启，请对麦克风说话观察电平', 'ok')
    } catch {
      toast('无法访问麦克风，请检查系统权限', 'warn')
    }
  }

  return (
    <div className="cfg-section">
      <div className="cfg-card">
        <div className="cfg-card-head">⌨️ 键盘测试</div>
        <div className="cfg-card-body">
          <p className="cfg-tip">
            点击下方区域使其获得焦点，然后敲击键盘（例如快速输入 123456789，或长按数字键观察）。
          </p>
          <div
            className={'cfg-input rc-test' + (kbdFocus ? ' focus' : '')}
            tabIndex={0}
            onFocus={() => setKbdFocus(true)}
            onBlur={() => setKbdFocus(false)}
          >
            {keys.length === 0 && <span className="cfg-tip">等待按键…（点击此区域获取焦点）</span>}
            {keys.map((k, i) => (
              <span key={i} className="rc-log-item">
                <b>{k.key}</b> <i>{k.code}</i> {k.t}
              </span>
            ))}
          </div>
          <button className="btn" onClick={() => setKeys([])}>
            🗑️ 清空记录
          </button>
        </div>
      </div>

      <div className="cfg-card">
        <div className="cfg-card-head">🔊 音箱测试</div>
        <div className="cfg-card-body">
          <p className="cfg-tip">点击按钮播放提示音，确认音箱接线与音量正常。</p>
          <div className="cfg-field">
            <label>测试音量（{Math.round(vol * 100)}%）</label>
            <div className="cfg-range">
              <input type="range" min={0} max={1} step={0.05} value={vol} onChange={(e) => setVol(Number(e.target.value))} />
              <span className="cfg-range-val">{Math.round(vol * 100)}%</span>
            </div>
          </div>
          <div className="pub-actions">
            <button className="btn accent" onClick={() => beep()}>
              🔊 播放提示音
            </button>
            <button className="btn" onClick={() => void playScale()}>
              🎵 播放音阶
            </button>
          </div>
        </div>
      </div>

      <div className="cfg-card">
        <div className="cfg-card-head">🎙️ 麦克风测试</div>
        <div className="cfg-card-body">
          <div className="pub-actions">
            <button className={'btn ' + (micOn ? 'danger' : 'primary')} onClick={() => void toggleMic()}>
              {micOn ? '⏹ 停止测试' : '🎙 开始测试'}
            </button>
          </div>
          <div className="mic-meter">
            <div className="mic-bar" style={{ width: level + '%', background: level > 70 ? '#e5484d' : level > 30 ? '#2f9e63' : '#3b82f6' }} />
          </div>
          <div className="mic-level">
            当前电平：<b>{level}%</b> {micOn ? '（对麦克风说话测试）' : '（未开启）'}
          </div>
        </div>
      </div>

      <div className="cfg-card">
        <div className="cfg-card-head">🖥️ 屏幕测试</div>
        <div className="cfg-card-body">
          <div className="pub-actions">
            <button className="btn accent" onClick={() => void detectScreens()}>
              📡 检测屏幕（显示编号标签）
            </button>
          </div>
          {screens.length === 0 ? (
            <p className="cfg-tip">未检测到屏幕。</p>
          ) : (
            <table className="cfg-table">
              <thead>
                <tr>
                  <th>编号</th>
                  <th>分辨率</th>
                  <th>位置</th>
                  <th>类型</th>
                  <th>当前播放</th>
                </tr>
              </thead>
              <tbody>
                {screens.map((s) => (
                  <tr key={s.index}>
                    <td>
                      屏幕 {s.index}
                      {s.primary && <span className="cfg-badge">主</span>}
                    </td>
                    <td>{s.res}</td>
                    <td>{s.pos}</td>
                    <td>{s.primary ? '主显示器' : '扩展屏'}</td>
                    <td>{s.playing ? s.playing.title : '空闲'}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </div>
  )
}
