// Shared utilities, hooks, SVGs and dummy data for all variants

// ----- i18n -----
const STRINGS = {
  ja: {
    appTitle: '消防緊急救護無線',
    appId: 'DATA119',
    map: 'MAP',
    video: '映像',
    chat: 'チャット',
    sos: 'SOS',
    ptt: 'PTT',
    camera: 'カメラ起動',
    emergencySos: '緊急SOS',
    talking: '発話中',
    videoDelivery: '映像配信',
    incidentSummary: '事案の概要',
    incidentType: '火災',
    address: '東京都港区芝5-X-X',
    dispatched: '出動隊',
    units: '5隊 17名',
    elapsed: '経過時間',
    squadCam: (n) => `第${n}小隊カメラ`,
    droneCam: '運航指揮隊ドローン',
    live: 'LIVE',
    releaseToSend: '離して送信',
    holdToTalk: '押して発話',
    sosConfirm: 'SOSを発信しますか？',
    sosSent: 'SOSを発信しました',
    cancel: 'キャンセル',
    send: '発信',
    cameraStarting: 'カメラ起動中…',
    youAreLive: '自端末から配信中',
    stopStreaming: '配信停止',
    now: 'たった今',
    team1: '第1小隊',
    team2: '第2小隊',
    team3: '第3小隊',
    command: '指揮隊',
    fire: '火災',
    chatMessages: [
      { t: '14:12', from: '指揮隊', text: '現場到着。これより放水開始。' },
      { t: '14:12', from: '第2小隊', text: '了解、第2小隊は西側へ。' },
      { t: '14:13', from: '第3小隊', text: '了解、北側へ回ります。' },
      { t: '14:14', from: '指揮隊', text: '[状態]：進入\n[報知]：放水開始' },
    ],
  },
  en: {
    appTitle: 'Fire Emergency Radio',
    appId: 'DATA119',
    map: 'MAP',
    video: 'VIDEO',
    chat: 'CHAT',
    sos: 'SOS',
    ptt: 'PTT',
    camera: 'CAMERA',
    emergencySos: 'Emergency SOS',
    talking: 'TALKING',
    videoDelivery: 'Streaming',
    incidentSummary: 'Incident Summary',
    incidentType: 'Structure Fire',
    address: 'Shiba 5-X-X, Minato-ku',
    dispatched: 'Units',
    units: '5 crews · 17 pax',
    elapsed: 'Elapsed',
    squadCam: (n) => `Squad ${n} Cam`,
    droneCam: 'Command Drone',
    live: 'LIVE',
    releaseToSend: 'Release to send',
    holdToTalk: 'Hold to talk',
    sosConfirm: 'Send SOS alert?',
    sosSent: 'SOS transmitted',
    cancel: 'Cancel',
    send: 'Send',
    cameraStarting: 'Starting camera…',
    youAreLive: 'Streaming from this unit',
    stopStreaming: 'Stop stream',
    now: 'now',
    team1: 'Squad 1',
    team2: 'Squad 2',
    team3: 'Squad 3',
    command: 'Command',
    fire: 'Fire',
    chatMessages: [
      { t: '14:12', from: 'Command', text: 'On scene. Begin suppression.' },
      { t: '14:12', from: 'Squad 2', text: 'Copy, Sq.2 moving to west side.' },
      { t: '14:13', from: 'Squad 3', text: 'Copy, rounding to north.' },
      { t: '14:14', from: 'Command', text: '[Status]: Entry\n[Advisory]: Water on' },
    ],
  },
};

// ----- Time tick hook -----
function useClock() {
  const [now, setNow] = React.useState(() => new Date());
  React.useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return now;
}

const pad = (n) => String(n).padStart(2, '0');
function fmtDateTime(d, lang) {
  if (lang === 'en') {
    return `${d.getFullYear()}/${pad(d.getMonth() + 1)}/${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
  }
  return `${d.getFullYear()}年${pad(d.getMonth() + 1)}月${pad(d.getDate())}日 ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

function fmtElapsed(seconds) {
  const m = Math.floor(seconds / 60);
  const s = seconds % 60;
  return `${pad(m)}:${pad(s)}`;
}

// ----- Icons (minimal, geometric only) -----
const IconSOS = ({ size = 20, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M12 3 L21 19 L3 19 Z" />
    <path d="M12 10 L12 14" />
    <circle cx="12" cy="16.5" r="0.6" fill={color} stroke="none" />
  </svg>
);

const IconMic = ({ size = 20, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <rect x="9" y="3" width="6" height="12" rx="3" />
    <path d="M5 11a7 7 0 0 0 14 0" />
    <path d="M12 18 L12 21" />
  </svg>
);

const IconSpeaker = ({ size = 20, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d="M4 9 L4 15 L8 15 L13 19 L13 5 L8 9 Z" />
    <path d="M16.5 8.5a5 5 0 0 1 0 7" />
    <path d="M19 6a8.5 8.5 0 0 1 0 12" />
  </svg>
);

const IconCam = ({ size = 20, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <rect x="2.5" y="6.5" width="14" height="11" rx="1.5" />
    <path d="M16.5 10.5 L21.5 7.5 L21.5 16.5 L16.5 13.5 Z" />
  </svg>
);

const IconChevron = ({ size = 14, color = 'currentColor', dir = 'right' }) => {
  const rot = { right: 0, down: 90, left: 180, up: 270 }[dir];
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" style={{ transform: `rotate(${rot}deg)` }}>
      <path d="M9 6 L15 12 L9 18" />
    </svg>
  );
};

const IconBattery = ({ size = 16 }) => (
  <svg width={size * 1.6} height={size} viewBox="0 0 26 16" fill="none">
    <rect x="1" y="2" width="20" height="12" rx="2.5" stroke="currentColor" strokeWidth="1.2" />
    <rect x="3" y="4" width="16" height="8" rx="1" fill="currentColor" />
    <rect x="22" y="6" width="2" height="4" rx="0.6" fill="currentColor" />
  </svg>
);

const IconSignal = ({ size = 14 }) => (
  <svg width={size} height={size} viewBox="0 0 16 16" fill="currentColor">
    <rect x="1" y="10" width="2.2" height="5" rx="0.3" />
    <rect x="5" y="7" width="2.2" height="8" rx="0.3" />
    <rect x="9" y="4" width="2.2" height="11" rx="0.3" />
    <rect x="13" y="1" width="2.2" height="14" rx="0.3" />
  </svg>
);

// ----- Map dummy team data (positions are % of container) -----
// Kept stable but slight drift animation can be applied
const TEAMS = [
  { id: 't1', label: '第1小隊', labelEn: 'Sq.1', x: 34, y: 42, color: '#2B7FFF', kind: 'unit' },
  { id: 't2', label: '第2小隊', labelEn: 'Sq.2', x: 58, y: 36, color: '#2B7FFF', kind: 'unit' },
  { id: 't3', label: '第3小隊', labelEn: 'Sq.3', x: 46, y: 62, color: '#2B7FFF', kind: 'unit' },
  { id: 'cmd', label: '指揮隊', labelEn: 'CMD', x: 50, y: 52, color: '#FFC64D', kind: 'cmd' },
  { id: 'drone', label: 'ドローン', labelEn: 'Drone', x: 52, y: 30, color: '#22D3EE', kind: 'drone' },
];

const FIRE_MARKER = { x: 50, y: 50 };

// ----- Mock Map SVG (dark themed) -----
function MockMap({ accent = '#FF6B2C', showGrid = true, dark = true, teamOffsets = {} }) {
  const bg = dark ? '#0D1116' : '#EEF0F2';
  const roadColor = dark ? '#2A2F38' : '#C8CDD3';
  const roadColorMinor = dark ? '#1E232B' : '#D7DCE2';
  const buildingColor = dark ? '#161B22' : '#DDE1E7';
  const buildingStroke = dark ? '#21262E' : '#C8CDD3';
  return (
    <svg viewBox="0 0 400 600" style={{ width: '100%', height: '100%', display: 'block' }} preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="600" fill={bg} />
      {/* subtle grid */}
      {showGrid && Array.from({ length: 12 }).map((_, i) => (
        <line key={'gv' + i} x1={i * 40} y1="0" x2={i * 40} y2="600" stroke={dark ? '#141820' : '#E5E8EC'} strokeWidth="0.5" />
      ))}
      {showGrid && Array.from({ length: 18 }).map((_, i) => (
        <line key={'gh' + i} x1="0" y1={i * 40} x2="400" y2={i * 40} stroke={dark ? '#141820' : '#E5E8EC'} strokeWidth="0.5" />
      ))}
      {/* buildings / blocks */}
      {[
        [20, 40, 90, 60], [130, 30, 70, 80], [220, 45, 90, 55], [330, 30, 60, 70],
        [25, 130, 80, 70], [140, 140, 100, 50], [260, 120, 110, 80],
        [30, 230, 70, 80], [130, 230, 90, 60], [240, 240, 60, 70], [320, 220, 60, 80],
        [20, 340, 100, 70], [150, 340, 80, 60], [260, 330, 110, 90],
        [30, 440, 70, 60], [130, 450, 90, 70], [250, 440, 130, 70],
        [40, 530, 100, 50], [180, 540, 80, 40], [290, 530, 90, 50],
      ].map(([x, y, w, h], i) => (
        <rect key={'b' + i} x={x} y={y} width={w} height={h} fill={buildingColor} stroke={buildingStroke} strokeWidth="0.6" rx="1.5" />
      ))}
      {/* main roads */}
      <rect x="0" y="105" width="400" height="18" fill={roadColor} />
      <rect x="0" y="310" width="400" height="16" fill={roadColor} />
      <rect x="0" y="415" width="400" height="16" fill={roadColor} />
      <rect x="113" y="0" width="18" height="600" fill={roadColor} />
      <rect x="306" y="0" width="16" height="600" fill={roadColor} />
      {/* minor roads */}
      <rect x="0" y="205" width="400" height="8" fill={roadColorMinor} />
      <rect x="0" y="505" width="400" height="8" fill={roadColorMinor} />
      <rect x="223" y="0" width="8" height="600" fill={roadColorMinor} />
      {/* hazard zone around fire */}
      <circle cx={FIRE_MARKER.x * 4} cy={FIRE_MARKER.y * 6} r="56" fill={accent} fillOpacity="0.12" stroke={accent} strokeOpacity="0.35" strokeWidth="1" strokeDasharray="4 3" />
      <circle cx={FIRE_MARKER.x * 4} cy={FIRE_MARKER.y * 6} r="32" fill={accent} fillOpacity="0.2" />
    </svg>
  );
}

// ----- Video placeholder -----
function VideoPlaceholder({ label, tone = 0, sub, dark = true, live = true, aspect = '16/10' }) {
  // tone is a hue offset 0..1 for variety
  const baseHue = 220 + tone * 50;
  const g1 = `hsl(${baseHue}, 22%, ${dark ? 14 : 78}%)`;
  const g2 = `hsl(${baseHue + 10}, 35%, ${dark ? 22 : 70}%)`;
  const g3 = `hsl(${baseHue + 25}, 28%, ${dark ? 9 : 85}%)`;
  return (
    <div style={{
      position: 'relative', width: '100%', aspectRatio: aspect, overflow: 'hidden',
      background: `linear-gradient(180deg, ${g1} 0%, ${g2} 60%, ${g3} 100%)`,
      borderRadius: 2,
    }}>
      {/* diagonal texture stripes */}
      <div style={{
        position: 'absolute', inset: 0,
        backgroundImage: `repeating-linear-gradient(135deg, rgba(255,255,255,0.02) 0 8px, rgba(0,0,0,0.04) 8px 16px)`,
        mixBlendMode: 'overlay',
      }} />
      {/* fake silhouette bars to suggest buildings */}
      <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, height: '45%', display: 'flex', alignItems: 'flex-end' }}>
        {[18, 36, 52, 28, 42, 60, 34, 48, 24, 38].map((h, i) => (
          <div key={i} style={{ flex: 1, height: `${h}%`, background: 'rgba(0,0,0,0.35)', marginRight: 1, borderTop: '1px solid rgba(255,255,255,0.05)' }} />
        ))}
      </div>
      {/* smoke wisps (SVG circles w/ blur) */}
      {tone < 0.5 && (
        <svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }} viewBox="0 0 160 100" preserveAspectRatio="none">
          <defs>
            <filter id={`blr-${tone}`}><feGaussianBlur stdDeviation="3" /></filter>
          </defs>
          <g filter={`url(#blr-${tone})`} opacity="0.5">
            <circle cx="60" cy="60" r="14" fill="#3a3028" />
            <circle cx="72" cy="52" r="18" fill="#4a3a30" />
            <circle cx="85" cy="58" r="12" fill="#2a2420" />
          </g>
          {/* ember glow */}
          <circle cx="72" cy="72" r="6" fill="#FF6B2C" opacity="0.55" filter={`url(#blr-${tone})`} />
        </svg>
      )}
      {/* label bottom-left */}
      <div style={{
        position: 'absolute', left: 8, bottom: 6,
        color: '#E6ECF2', fontSize: 10, fontWeight: 600, letterSpacing: 0.3,
        textShadow: '0 1px 2px rgba(0,0,0,0.6)', fontFamily: 'Inter, sans-serif',
      }}>
        {label}
        {sub && <span style={{ opacity: 0.75, marginLeft: 6, fontWeight: 400 }}>{sub}</span>}
      </div>
      {live && (
        <div style={{
          position: 'absolute', right: 8, top: 6, display: 'flex', alignItems: 'center', gap: 4,
          background: 'rgba(0,0,0,0.55)', padding: '2px 6px', borderRadius: 2,
          fontFamily: 'JetBrains Mono, monospace', fontSize: 9, color: '#fff', fontWeight: 700, letterSpacing: 0.6,
        }}>
          <span style={{ width: 6, height: 6, borderRadius: 999, background: '#EF4444', animation: 'pulseDot 1.2s ease-in-out infinite' }} />
          LIVE
        </div>
      )}
    </div>
  );
}

// ----- PTT hook: press-and-hold timer & waveform samples -----
function usePttHold(enabled = true) {
  const [holding, setHolding] = React.useState(false);
  const [holdSec, setHoldSec] = React.useState(0);
  const startRef = React.useRef(0);
  const rafRef = React.useRef(0);
  const [waveSamples, setWaveSamples] = React.useState(() => new Array(32).fill(0));

  const tick = React.useCallback(() => {
    const elapsed = (performance.now() - startRef.current) / 1000;
    setHoldSec(elapsed);
    setWaveSamples(prev => {
      const next = prev.slice(1);
      // pseudo-random amplitude, more energy while holding
      next.push(0.25 + Math.random() * 0.75);
      return next;
    });
    rafRef.current = requestAnimationFrame(tick);
  }, []);

  const begin = React.useCallback(() => {
    if (!enabled) return;
    if (holding) return;
    startRef.current = performance.now();
    setHolding(true);
    setHoldSec(0);
    rafRef.current = requestAnimationFrame(tick);
  }, [enabled, holding, tick]);

  const end = React.useCallback(() => {
    if (!holding) return;
    cancelAnimationFrame(rafRef.current);
    setHolding(false);
    // decay waves
    let decayId;
    const decay = () => {
      setWaveSamples(prev => {
        const next = prev.map(v => v * 0.85);
        if (Math.max(...next) < 0.02) {
          return new Array(32).fill(0);
        }
        decayId = requestAnimationFrame(decay);
        return next;
      });
    };
    decayId = requestAnimationFrame(decay);
  }, [holding]);

  React.useEffect(() => () => cancelAnimationFrame(rafRef.current), []);

  return { holding, holdSec, waveSamples, begin, end };
}

// ----- Waveform renderer -----
function Waveform({ samples, color = '#34D399', height = 32, bars = 32 }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 2, height, width: '100%' }}>
      {samples.slice(-bars).map((v, i) => (
        <div key={i} style={{
          width: 3, height: `${Math.max(6, v * height)}px`,
          background: color, borderRadius: 2, opacity: 0.55 + v * 0.45,
          transition: 'height 60ms linear',
        }} />
      ))}
    </div>
  );
}

// ----- Status bar (mimics iOS top area) -----
function StatusBar({ color = '#E6ECF2' }) {
  const now = useClock();
  return (
    <div style={{
      display: 'flex', justifyContent: 'space-between', alignItems: 'center',
      padding: '14px 22px 6px', color, fontFamily: 'Inter, sans-serif',
      fontSize: 14, fontWeight: 600,
    }}>
      <span style={{ fontVariantNumeric: 'tabular-nums' }}>{pad(now.getHours())}:{pad(now.getMinutes())}</span>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
        <IconSignal />
        <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: 0.2 }}>5G</span>
        <IconBattery />
      </div>
    </div>
  );
}

// expose
Object.assign(window, {
  STRINGS, useClock, fmtDateTime, fmtElapsed, pad,
  IconSOS, IconMic, IconCam, IconChevron, IconBattery, IconSignal,
  TEAMS, FIRE_MARKER, MockMap, VideoPlaceholder,
  usePttHold, Waveform, StatusBar,
});
