'use client'

import { useState, useEffect, useCallback, useRef } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Thermometer, Droplets, Wind, Calendar, Lock, Settings as SettingsIcon, LogOut, Delete, KeyRound, MapPin, Info, Check, X as XIcon, StickyNote, ShoppingCart, FileText } from 'lucide-react'
import Sidebar from '@/components/Sidebar'
import TopBar from '@/components/TopBar'
import RoomTabs from '@/components/RoomTabs'
import DeviceCard from '@/components/DeviceCard'
import CalendarTab from '@/components/CalendarTab'
import NotesTab from '@/components/NotesTab'
import TransportWidget from '@/components/TransportWidget'
import WeatherAnimation from '@/components/WeatherAnimation'
import VoiceOverlay from '@/components/VoiceOverlay'
import VoiceController from '@/components/VoiceController'
import TimerWidget from '@/components/TimerWidget'
import TimerHomeWidget from '@/components/TimerHomeWidget'
import SpotifyWidget from '@/components/SpotifyWidget'

type Tab = 'home' | 'devices' | 'calendar' | 'notes' | 'settings'

const TAB_ORDER: Tab[] = ['home', 'devices', 'calendar', 'notes', 'settings']

interface WeatherData {
  temp: string
  desc: string
  humidity: string
  windSpeed: string
  feelsLike: string
  forecast?: { date: string; maxTemp: string; minTemp: string; desc: string; feelsLikeMax?: string; feelsLikeMin?: string; precipProb?: string; windSpeed?: string; humidity?: string }[]
}

interface SensorData {
  temperature: number
  humidity: number
  pm25: number
}

interface HaStates {
  [key: string]: { state: string; attributes?: Record<string, any>; _mock?: boolean }
}

interface CalendarEvent {
  id: string
  title: string
  start: string
  end: string
  allDay: boolean
  owner: string
  ownerName: string
  color: string
}

const ROOMS = [
  { id: 'living', name: 'Гостиная', emoji: '🛋️', deviceCount: 3 },
  { id: 'bedroom', name: 'Спальня', emoji: '🛏️', deviceCount: 2 },
  { id: 'kitchen', name: 'Кухня', emoji: '🍳', deviceCount: 0 },
  { id: 'bathroom', name: 'Ванная', emoji: '🚿', deviceCount: 0 },
]

const DEVICES_BY_ROOM: Record<string, {
  id: string; name: string; icon: string
  entityId?: string; domain?: string; haKey?: string; isMock?: boolean
}[]> = {
  living: [
    { id: 'air_purifier', name: 'Очиститель воздуха', icon: '💨', entityId: 'fan.zhimi_rmb1_9528_air_purifier', domain: 'fan', haKey: 'fan.air_purifier', isMock: false },
    { id: 'light_living', name: 'Свет', icon: '💡', entityId: 'light.living_room', domain: 'light', haKey: 'light.living_room', isMock: true },
    { id: 'tv', name: 'Телевизор', icon: '📺', isMock: true },
  ],
  bedroom: [
    { id: 'light_bedroom', name: 'Свет', icon: '💡', entityId: 'light.bedroom', domain: 'light', haKey: 'light.bedroom', isMock: true },
    { id: 'ac', name: 'Кондиционер', icon: '❄️', isMock: true },
  ],
  kitchen: [],
  bathroom: [],
}

const CITIES = [
  { id: 'spb', name: 'Санкт-Петербург', lat: '59.9343', lon: '30.3351' },
  { id: 'msk', name: 'Москва', lat: '55.7558', lon: '37.6173' },
  { id: 'nsk', name: 'Новосибирск', lat: '55.0084', lon: '82.9357' },
  { id: 'ekb', name: 'Екатеринбург', lat: '56.8389', lon: '60.6057' },
  { id: 'kzn', name: 'Казань', lat: '55.7887', lon: '49.1221' },
  { id: 'sochi', name: 'Сочи', lat: '43.5855', lon: '39.7231' },
  { id: 'krd', name: 'Краснодар', lat: '45.0355', lon: '38.9753' },
]

function getWeatherIcon(desc: string): string {
  const d = desc?.toLowerCase() || ''
  if (d.includes('ясно') || d.includes('солнеч')) return '☀️'
  if (d.includes('облач') || d.includes('перем')) return '⛅'
  if (d.includes('пасмурн')) return '☁️'
  if (d.includes('дождь') || d.includes('морос') || d.includes('ливен')) return '🌧️'
  if (d.includes('снег')) return '🌨️'
  if (d.includes('гроз')) return '⛈️'
  if (d.includes('туман')) return '🌫️'
  return '🌤️'
}

function formatEventTime(iso: string): string {
  return new Date(iso).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })
}

function getWeatherBgClass(desc: string | null): string {
  if (!desc) return ''
  const d = desc.toLowerCase()
  const hour = new Date().getHours()
  if (hour >= 22 || hour < 5) return 'weather-bg-night'
  if (d.includes('гроз')) return 'weather-bg-thunder'
  if (d.includes('снег')) return 'weather-bg-snow'
  if (d.includes('дождь') || d.includes('ливен') || d.includes('морос')) return 'weather-bg-rain'
  if (d.includes('пасмурн') || d.includes('облач') || d.includes('туман')) return 'weather-bg-cloudy'
  return 'weather-bg-clear'
}

function getGreeting(): string {
  const h = new Date().getHours()
  if (h >= 5 && h < 12) return 'Доброе утро'
  if (h >= 12 && h < 17) return 'Добрый день'
  if (h >= 17 && h < 22) return 'Добрый вечер'
  return 'Доброй ночи'
}

function getPm25Level(pm25: number): { label: string; color: string; bg: string } {
  if (pm25 <= 12) return { label: 'Отлично', color: '#34d399', bg: 'rgba(52,211,153,0.12)' }
  if (pm25 <= 35) return { label: 'Хорошо', color: '#a3e635', bg: 'rgba(163,230,53,0.12)' }
  if (pm25 <= 55) return { label: 'Умеренно', color: '#fbbf24', bg: 'rgba(251,191,36,0.12)' }
  return { label: 'Плохо', color: '#f87171', bg: 'rgba(248,113,113,0.12)' }
}

// ————— Screensaver —————
function Screensaver({ weather, onDismiss }: { weather: WeatherData | null; onDismiss: () => void }) {
  const [time, setTime] = useState(new Date())

  useEffect(() => {
    const t = setInterval(() => setTime(new Date()), 1000)
    return () => clearInterval(t)
  }, [])

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: 0.8 }}
      onClick={onDismiss}
      onTouchStart={onDismiss}
      style={{
        position: 'fixed', inset: 0, zIndex: 200,
        background: '#050510',
        display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        cursor: 'pointer', gap: 24,
      }}
    >
      {/* Subtle ambient */}
      <div style={{
        position: 'absolute', width: 400, height: 400, borderRadius: '50%',
        background: 'radial-gradient(circle, rgba(99,102,241,0.06) 0%, transparent 70%)',
        animation: 'float1 20s ease-in-out infinite',
      }} />

      {/* Time */}
      <div style={{
        fontSize: 120, fontWeight: 800, color: 'rgba(255,255,255,0.9)',
        letterSpacing: '-6px', fontVariantNumeric: 'tabular-nums',
        lineHeight: 1, textShadow: '0 0 60px rgba(99,102,241,0.2)',
      }}>
        {time.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })}
      </div>

      {/* Date */}
      <div style={{
        fontSize: 22, color: 'rgba(255,255,255,0.35)',
        fontWeight: 500, textTransform: 'capitalize',
      }}>
        {time.toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' })}
      </div>

      {/* Weather mini */}
      {weather && (
        <div style={{
          display: 'flex', alignItems: 'center', gap: 12,
          marginTop: 16, color: 'rgba(255,255,255,0.3)',
        }}>
          <WeatherAnimation condition={weather.desc} size={36} />
          <span style={{ fontSize: 24, fontWeight: 600 }}>{weather.temp}°</span>
          <span style={{ fontSize: 16 }}>{weather.desc}</span>
        </div>
      )}

      <div style={{
        position: 'absolute', bottom: 40,
        fontSize: 13, color: 'rgba(255,255,255,0.15)',
      }}>
        Коснитесь для разблокировки
      </div>
    </motion.div>
  )
}

// ————— Lock Screen —————
function LockScreen({ onUnlock }: { onUnlock: () => void }) {
  const [pin, setPin] = useState('')
  const [error, setError] = useState(false)
  const [loading, setLoading] = useState(false)
  const [time, setTime] = useState(new Date())

  useEffect(() => {
    const t = setInterval(() => setTime(new Date()), 1000)
    return () => clearInterval(t)
  }, [])

  const submit = async (fullPin: string) => {
    setLoading(true); setError(false)
    try {
      const r = await fetch('/api/auth', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ pin: fullPin }),
      })
      if (r.ok) onUnlock()
      else { setError(true); setPin(''); setTimeout(() => setError(false), 1500) }
    } catch { setError(true); setPin('') }
    finally { setLoading(false) }
  }

  const handleDigit = (d: string) => {
    if (pin.length >= 6) return
    const next = pin + d
    setPin(next)
    if (next.length === 4) submit(next)
  }

  const digits = ['1','2','3','4','5','6','7','8','9','','0','del']

  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 200, background: '#0c0c18',
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 40,
    }}>
      <div className="bg-ambient"><div className="aurora-3" /></div>
      <div style={{ textAlign: 'center', position: 'relative', zIndex: 1 }}>
        <div style={{ fontSize: 64, fontWeight: 800, color: 'var(--text-primary)', letterSpacing: '-3px', fontVariantNumeric: 'tabular-nums' }}>
          {time.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })}
        </div>
        <div style={{ fontSize: 16, color: 'var(--text-secondary)', marginTop: 4, textTransform: 'capitalize', fontWeight: 500 }}>
          {time.toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' })}
        </div>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20, position: 'relative', zIndex: 1 }}>
        <div style={{
          width: 56, height: 56, borderRadius: 18,
          background: error ? 'rgba(239,68,68,0.15)' : 'linear-gradient(135deg, rgba(99,102,241,0.2), rgba(139,92,246,0.15))',
          border: error ? '1px solid rgba(239,68,68,0.3)' : '1px solid rgba(129,140,248,0.25)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.3s ease',
        }}>
          <Lock size={24} color={error ? '#f87171' : '#a5b4fc'} />
        </div>
        <div style={{ display: 'flex', gap: 14 }}>
          {[0,1,2,3].map(i => (
            <div key={i} style={{
              width: 14, height: 14, borderRadius: '50%',
              background: i < pin.length ? (error ? '#f87171' : '#a5b4fc') : 'rgba(255,255,255,0.1)',
              border: `1px solid ${i < pin.length ? (error ? 'rgba(239,68,68,0.5)' : 'rgba(165,180,252,0.5)') : 'rgba(255,255,255,0.15)'}`,
              transition: 'all 0.2s ease', transform: i < pin.length ? 'scale(1.15)' : 'scale(1)',
            }} />
          ))}
        </div>
        {error && <div style={{ fontSize: 13, color: '#f87171', fontWeight: 500 }}>Неверный PIN</div>}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, position: 'relative', zIndex: 1 }}>
        {digits.map((d, i) => {
          if (d === '') return <div key={i} />
          if (d === 'del') return (
            <button key={i} onClick={() => setPin(p => p.slice(0, -1))} style={{
              width: 72, height: 72, borderRadius: 20, background: 'rgba(255,255,255,0.03)',
              border: '1px solid rgba(255,255,255,0.06)', display: 'flex', alignItems: 'center', justifyContent: 'center',
              color: 'var(--text-secondary)', transition: 'all 0.15s ease',
            }}><Delete size={22} /></button>
          )
          return (
            <button key={i} onClick={() => handleDigit(d)} style={{
              width: 72, height: 72, borderRadius: 20, background: 'rgba(255,255,255,0.04)',
              border: '1px solid rgba(255,255,255,0.07)', fontSize: 24, fontWeight: 600,
              color: 'var(--text-primary)', transition: 'all 0.15s ease',
            }}>{d}</button>
          )
        })}
      </div>
    </div>
  )
}

// ————— Home Tab —————
// ————— Weather Day Detail Modal —————
type ForecastDay = { date: string; maxTemp: string; minTemp: string; desc: string; feelsLikeMax?: string; feelsLikeMin?: string; precipProb?: string; windSpeed?: string; humidity?: string }

function WeatherDayModal({ day, days, current, onClose, onChange }: {
  day: ForecastDay
  days: ForecastDay[]
  current: WeatherData | null
  onClose: () => void
  onChange: (d: ForecastDay) => void
}) {
  const d = new Date(day.date)
  const isToday = d.toDateString() === new Date().toDateString()
  const dayLabel = isToday ? 'Сегодня' : d.toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' })
  const idx = days.findIndex(x => x.date === day.date)
  const canPrev = idx > 0
  const canNext = idx >= 0 && idx < days.length - 1
  const go = (delta: number) => {
    const next = days[idx + delta]
    if (next) onChange(next)
  }

  return (
    <div data-swipe-ignore style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', backdropFilter: 'blur(12px)', zIndex: 100, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }} onClick={onClose}>
      <motion.div
        key={day.date}
        drag="x"
        dragConstraints={{ left: 0, right: 0 }}
        dragElastic={0.15}
        onDragEnd={(_, info) => {
          if (info.offset.x < -60 && canNext) go(1)
          else if (info.offset.x > 60 && canPrev) go(-1)
        }}
        initial={{ opacity: 0, scale: 0.96 }}
        animate={{ opacity: 1, scale: 1 }}
        transition={{ type: 'spring', stiffness: 320, damping: 28 }}
        style={{
          background: 'var(--surface-1)',
          border: '1px solid var(--border-subtle)', borderRadius: 28,
          width: 420, maxWidth: '90vw', overflow: 'hidden',
          boxShadow: 'var(--shadow-xl)',
          touchAction: 'pan-y',
        }}
        onClick={e => e.stopPropagation()}
      >

        {/* Hero */}
        <div style={{
          background: 'linear-gradient(135deg, var(--accent-glow), transparent)',
          borderBottom: '1px solid var(--hairline)',
          padding: '24px 28px 22px', textAlign: 'center',
          position: 'relative', overflow: 'hidden',
        }}>
          {/* Prev/Next chevrons */}
          {canPrev && (
            <button
              onClick={() => go(-1)}
              aria-label="Предыдущий день"
              style={{
                position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)',
                width: 48, height: 48, borderRadius: 14,
                background: 'var(--surface-2)', border: '1px solid var(--border-subtle)',
                color: 'var(--text-secondary)', zIndex: 2, fontSize: 22,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}
            >‹</button>
          )}
          {canNext && (
            <button
              onClick={() => go(1)}
              aria-label="Следующий день"
              style={{
                position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)',
                width: 48, height: 48, borderRadius: 14,
                background: 'var(--surface-2)', border: '1px solid var(--border-subtle)',
                color: 'var(--text-secondary)', zIndex: 2, fontSize: 22,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}
            >›</button>
          )}
          <div style={{ position: 'absolute', top: -10, right: 10, opacity: 0.1, pointerEvents: 'none' }}>
            <WeatherAnimation condition={day.desc} size={100} />
          </div>
          <div style={{ position: 'relative', zIndex: 1 }}>
            <div style={{ fontSize: 14, color: 'var(--text-secondary)', fontWeight: 500, textTransform: 'capitalize', marginBottom: 12 }}>{dayLabel}</div>
            <WeatherAnimation condition={day.desc} size={64} />
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 8, marginTop: 12 }}>
              <span style={{ fontSize: 42, fontWeight: 800, color: 'var(--text-primary)', letterSpacing: '-2px' }}>{day.maxTemp}°</span>
              <span style={{ fontSize: 22, fontWeight: 500, color: 'var(--text-secondary)' }}>{day.minTemp}°</span>
            </div>
            <div style={{ fontSize: 15, color: 'var(--text-secondary)', marginTop: 6, fontWeight: 500 }}>{day.desc}</div>
          </div>
        </div>

        {/* Details grid */}
        <div style={{ padding: '20px 24px 20px' }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 10 }}>
            {[
              { icon: <Thermometer size={18} color="#fb923c" />, bg: 'rgba(251,146,60,0.1)', label: 'Ощущается', value: `${day.feelsLikeMax || '—'}° / ${day.feelsLikeMin || '—'}°` },
              { icon: <Droplets size={18} color="#3b82f6" />, bg: 'rgba(59,130,246,0.1)', label: 'Влажность', value: `${day.humidity || (isToday && current ? current.humidity : '—')}%` },
              { icon: <Wind size={18} color="#22d3ee" />, bg: 'rgba(34,211,238,0.1)', label: 'Ветер', value: `${day.windSpeed || (isToday && current ? current.windSpeed : '—')} м/с` },
              { icon: <span style={{ fontSize: 18 }}>🌧️</span>, bg: 'rgba(99,102,241,0.1)', label: 'Осадки', value: `${day.precipProb || '0'}%` },
            ].map(item => (
              <div key={item.label} style={{
                padding: '14px 12px', borderRadius: 14,
                background: 'var(--surface-2)', border: '1px solid var(--border-subtle)',
                display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6,
              }}>
                <div style={{
                  width: 36, height: 36, borderRadius: 11, background: item.bg,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}>{item.icon}</div>
                <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--text-primary)' }}>{item.value}</div>
                <div style={{ fontSize: 11, color: 'var(--text-secondary)', textAlign: 'center' }}>{item.label}</div>
              </div>
            ))}
          </div>

          {/* Dot indicator */}
          {days.length > 1 && (
            <div style={{ display: 'flex', gap: 5, justifyContent: 'center', marginTop: 14 }}>
              {days.map((di, i) => (
                <button
                  key={di.date}
                  onClick={() => onChange(di)}
                  style={{
                    width: i === idx ? 18 : 6, height: 6, borderRadius: 3,
                    background: i === idx ? 'var(--accent)' : 'var(--surface-3)',
                    transition: 'all 0.25s ease',
                  }}
                />
              ))}
            </div>
          )}

          <button onClick={onClose} style={{
            width: '100%', padding: '16px', borderRadius: 14, marginTop: 12,
            minHeight: 48,
            background: 'var(--surface-2)', border: '1px solid var(--border-subtle)',
            color: 'var(--text-secondary)', fontSize: 14, fontWeight: 600,
          }}>
            Закрыть
          </button>
        </div>
      </motion.div>
    </div>
  )
}


function HomeTab({ weather, sensors }: { weather: WeatherData | null; sensors: SensorData | null }) {
  const [todayEvents, setTodayEvents] = useState<CalendarEvent[]>([])
  const [tomorrowEvents, setTomorrowEvents] = useState<CalendarEvent[]>([])
  const [calLoading, setCalLoading] = useState(true)
  const [pinnedNotes, setPinnedNotes] = useState<any[]>([])
  const [selectedDay, setSelectedDay] = useState<any>(null)

  useEffect(() => {
    fetch('/api/calendar?range=today')
      .then(r => r.json())
      .then(d => setTodayEvents(d.events || []))
      .catch(() => setTodayEvents([]))
      .finally(() => setCalLoading(false))

    // Tomorrow
    const tomorrow = new Date()
    tomorrow.setDate(tomorrow.getDate() + 1)
    const y = tomorrow.getFullYear()
    const m = tomorrow.getMonth()
    fetch(`/api/calendar?range=month&year=${y}&month=${m}`)
      .then(r => r.json())
      .then(d => {
        const tmr = (d.events || []).filter((e: any) => {
          const ed = new Date(e.start)
          return ed.getDate() === tomorrow.getDate() && ed.getMonth() === tomorrow.getMonth()
        })
        setTomorrowEvents(tmr)
      })
      .catch(() => {})

    // Notes — pinned (pinDate today or future), fallback to latest
    fetch('/api/notes')
      .then(r => r.json())
      .then(d => {
        const all = d.notes || []
        const today = new Date(); today.setHours(0, 0, 0, 0)
        const pinned = all.filter((n: any) => {
          if (!n.pinDate) return false
          const pd = new Date(n.pinDate); pd.setHours(0, 0, 0, 0)
          return pd.getTime() >= today.getTime()
        })
        setPinnedNotes((pinned.length ? pinned : all).slice(0, 3))
      })
      .catch(() => {})

  }, [])



  return (
    <div style={{
      flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch' as any,
      padding: '18px 22px 24px',
      display: 'flex', flexDirection: 'column', gap: 14,
    }}>
      {/* ───── Bento row: Hero weather + Tram ───── */}
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1.1fr)', gap: 14, alignItems: 'stretch' }}>

        {/* Hero weather card */}
        {weather ? (
          <div
            className="card-hero"
            onClick={() => weather?.forecast?.[0] && setSelectedDay(weather.forecast[0])}
            style={{
              padding: '24px 26px',
              display: 'flex', flexDirection: 'column',
              position: 'relative', overflow: 'hidden',
              cursor: 'pointer',
            }}
          >
            {/* Decorative animation, large, behind */}
            <div style={{
              position: 'absolute', top: -24, right: -12,
              opacity: 0.14, pointerEvents: 'none',
            }}>
              <WeatherAnimation condition={weather.desc} size={180} />
            </div>

            <div className="eyebrow" style={{ marginBottom: 10, position: 'relative', zIndex: 1 }}>
              Сейчас
            </div>

            <div style={{
              display: 'flex', alignItems: 'center', gap: 14,
              position: 'relative', zIndex: 1, marginBottom: 8,
            }}>
              <div className="num-display" style={{
                fontSize: 76, color: 'var(--text-primary)',
              }}>
                {weather.temp}°
              </div>
              <WeatherAnimation condition={weather.desc} size={60} />
            </div>

            <div style={{
              fontSize: 17, color: 'var(--text-primary)', fontWeight: 600,
              position: 'relative', zIndex: 1, marginBottom: 16,
              textTransform: 'capitalize',
            }}>
              {weather.desc}
            </div>

            <div style={{
              display: 'flex', gap: 22, flexWrap: 'wrap',
              marginTop: 'auto', position: 'relative', zIndex: 1,
            }}>
              {weather.feelsLike && (
                <div>
                  <div className="eyebrow">Ощущается</div>
                  <div className="num" style={{ fontSize: 16, color: 'var(--text-primary)', fontWeight: 700, marginTop: 3 }}>{weather.feelsLike}°</div>
                </div>
              )}
              {weather.humidity && (
                <div>
                  <div className="eyebrow">Влажность</div>
                  <div className="num" style={{ fontSize: 16, color: 'var(--text-primary)', fontWeight: 700, marginTop: 3 }}>{weather.humidity}</div>
                </div>
              )}
              {weather.windSpeed && (
                <div>
                  <div className="eyebrow">Ветер</div>
                  <div className="num" style={{ fontSize: 16, color: 'var(--text-primary)', fontWeight: 700, marginTop: 3 }}>{weather.windSpeed}</div>
                </div>
              )}
            </div>
          </div>
        ) : (
          <div className="card-hero" style={{ padding: '24px 26px', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-tertiary)', fontSize: 13 }}>
            Загрузка погоды...
          </div>
        )}

        {/* Tram */}
        <TransportWidget />
      </div>

      {/* ───── Forecast band (no cards, hairline-separated) ───── */}
      {weather?.forecast && (
        <div className="card" style={{
          padding: '12px 6px',
          display: 'flex', alignItems: 'stretch',
        }}>
          {weather.forecast.map((day, idx) => {
            const d = new Date(day.date)
            const isToday = idx === 0
            return (
              <div key={day.date} style={{
                flex: 1, display: 'flex', alignItems: 'stretch',
                borderRight: idx < weather.forecast!.length - 1 ? '1px solid var(--hairline)' : 'none',
              }}>
                <button
                  onClick={() => setSelectedDay(day)}
                  style={{
                    flex: 1, padding: '12px 8px', borderRadius: 14,
                    minHeight: 92,
                    background: isToday ? 'var(--surface-2)' : 'transparent',
                    display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6,
                    transition: 'background 0.2s ease',
                  }}
                >
                  <div style={{
                    fontSize: 11, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase',
                    color: isToday ? 'var(--accent)' : 'var(--text-tertiary)',
                  }}>
                    {isToday ? 'Сей' : d.toLocaleDateString('ru-RU', { weekday: 'short' }).replace('.', '').slice(0, 2)}
                  </div>
                  <div style={{ fontSize: 22 }}>{getWeatherIcon(day.desc)}</div>
                  <div className="num" style={{
                    fontSize: 15, fontWeight: 800, color: 'var(--text-primary)',
                    letterSpacing: '-0.5px',
                  }}>
                    {day.maxTemp}°
                  </div>
                  <div className="num" style={{
                    fontSize: 12, color: 'var(--text-tertiary)', fontWeight: 500,
                  }}>
                    {day.minTemp}°
                  </div>
                </button>
              </div>
            )
          })}
        </div>
      )}

      {/* ───── Events + Timers row ───── */}
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: 14 }}>

        {/* Events — today + tomorrow in one card */}
        <div className="card" style={{ padding: '18px 20px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          {/* Today */}
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
              <Calendar size={13} color="var(--text-secondary)" />
              <span style={{ fontSize: 10, color: 'var(--text-secondary)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 700 }}>Сегодня</span>
              <span style={{
                fontSize: 10, color: 'var(--text-tertiary)',
                background: 'var(--surface-2)', padding: '2px 7px', borderRadius: 8,
                fontWeight: 700, fontVariantNumeric: 'tabular-nums',
              }}>
                {todayEvents.length}
              </span>
            </div>
            {calLoading ? (
              <div style={{ fontSize: 13, color: 'var(--text-tertiary)' }}>Загрузка...</div>
            ) : todayEvents.length === 0 ? (
              <div style={{ fontSize: 14, color: 'var(--text-tertiary)', textAlign: 'center', padding: '6px 0' }}>Свободный день ✨</div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                {todayEvents.map(ev => (
                  <div key={ev.id} style={{
                    display: 'flex', alignItems: 'center', gap: 10,
                    padding: '8px 10px', borderRadius: 12,
                    background: 'var(--surface-2)',
                    border: '1px solid var(--border-subtle)',
                  }}>
                    <div style={{ width: 3, borderRadius: 2, background: ev.color, alignSelf: 'stretch', minHeight: 28, flexShrink: 0 }} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ev.title}</div>
                      <div style={{ fontSize: 11, color: 'var(--text-secondary)', marginTop: 2 }}>
                        {ev.allDay ? 'Весь день' : formatEventTime(ev.start)} · <span style={{ color: ev.color, fontWeight: 600 }}>{ev.ownerName}</span>
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>

          {/* Divider */}
          {(tomorrowEvents.length > 0 || todayEvents.length > 0) && (
            <div style={{ height: 1, background: 'var(--hairline)' }} />
          )}

          {/* Tomorrow */}
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
              <Calendar size={13} color="var(--text-tertiary)" />
              <span style={{ fontSize: 10, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 700 }}>Завтра</span>
              <span style={{
                fontSize: 10, color: 'var(--text-tertiary)',
                background: 'var(--surface-2)', padding: '2px 7px', borderRadius: 8,
                fontWeight: 700, fontVariantNumeric: 'tabular-nums',
              }}>
                {tomorrowEvents.length}
              </span>
            </div>
            {tomorrowEvents.length === 0 ? (
              <div style={{ fontSize: 13, color: 'var(--text-tertiary)', textAlign: 'center', padding: '4px 0' }}>—</div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
                {tomorrowEvents.map(ev => (
                  <div key={ev.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 10px' }}>
                    <div style={{ width: 3, borderRadius: 2, background: ev.color, alignSelf: 'stretch', minHeight: 22, flexShrink: 0, opacity: 0.7 }} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ev.title}</div>
                      <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 1 }}>
                        {ev.allDay ? 'Весь день' : formatEventTime(ev.start)}
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* Timers (replaces Notes on Home) */}
        <TimerHomeWidget />
      </div>

      {/* ───── Spotify ───── */}
      <SpotifyWidget />

      {/* Weather day detail modal */}
      {selectedDay && (
        <WeatherDayModal
          day={selectedDay}
          days={weather?.forecast || []}
          current={weather}
          onClose={() => setSelectedDay(null)}
          onChange={setSelectedDay}
        />
      )}
    </div>
  )
}


// ————— Settings Tab —————
function SettingsTab({ city, onCityChange, onLogout, theme, onThemeChange }: { city: string; onCityChange: (id: string) => void; onLogout: () => void; theme: string; onThemeChange: (t: string) => void }) {
  const [showPinChange, setShowPinChange] = useState(false)
  const [oldPin, setOldPin] = useState('')
  const [newPin, setNewPin] = useState('')
  const [pinMsg, setPinMsg] = useState<{ text: string; ok: boolean } | null>(null)
  const [pinSaving, setPinSaving] = useState(false)

  const changePIN = async () => {
    if (!oldPin || !newPin) { setPinMsg({ text: 'Заполните оба поля', ok: false }); return }
    if (newPin.length < 4) { setPinMsg({ text: 'Минимум 4 цифры', ok: false }); return }
    setPinSaving(true); setPinMsg(null)
    try {
      const r = await fetch('/api/auth', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ oldPin, newPin }),
      })
      const d = await r.json()
      if (d.error) throw new Error(d.error === 'wrong_pin' ? 'Неверный старый PIN' : d.error)
      setPinMsg({ text: 'PIN изменён', ok: true })
      setOldPin(''); setNewPin('')
      setTimeout(() => { setShowPinChange(false); setPinMsg(null) }, 1500)
    } catch (e: any) { setPinMsg({ text: e.message, ok: false }) }
    finally { setPinSaving(false) }
  }

  const inputStyle: React.CSSProperties = {
    padding: '14px 18px', borderRadius: 14, width: '100%',
    background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.07)',
    color: 'var(--text-primary)', fontSize: 15, outline: 'none', fontFamily: 'inherit',
    textAlign: 'center', letterSpacing: '4px',
  }

  const [voiceProvider, setVoiceProvider] = useState<'anthropic' | 'groq'>('anthropic')

  useEffect(() => {
    fetch('/api/settings').then(r => r.json()).then(s => {
      setVoiceProvider(s.voiceProvider || 'anthropic')
    }).catch(() => {})
  }, [])

  const handleProviderChange = async (p: 'anthropic' | 'groq') => {
    setVoiceProvider(p)
    await fetch('/api/settings', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ voiceProvider: p }),
    }).catch(() => {})
  }

  const currentCity = CITIES.find(c => c.id === city) || CITIES[0]

  return (
    <div style={{ flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch' as any, touchAction: 'pan-y', padding: '24px', display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 560, margin: '0 auto', width: '100%' }}>
      <h2 style={{ fontSize: 24, fontWeight: 800, color: 'var(--text-primary)', margin: '0 0 8px', letterSpacing: '-0.5px' }}>Настройки</h2>

      {/* Голосовой агент */}
      <div style={{ background: 'var(--card-bg)', border: '1px solid var(--card-border)', borderRadius: 22, padding: '22px 24px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
          <span style={{ fontSize: 18 }}>🤖</span>
          <span style={{ fontSize: 15, fontWeight: 600, color: 'var(--text-primary)' }}>Голосовой агент</span>
        </div>
        <div style={{ display: 'flex', gap: 10 }}>
          {(['anthropic', 'groq'] as const).map(p => (
            <button
              key={p}
              onClick={() => handleProviderChange(p)}
              style={{
                flex: 1, padding: '12px 0', borderRadius: 14,
                background: voiceProvider === p ? 'rgba(99,102,241,0.15)' : 'rgba(255,255,255,0.03)',
                border: `1px solid ${voiceProvider === p ? 'rgba(99,102,241,0.4)' : 'rgba(255,255,255,0.07)'}`,
                color: voiceProvider === p ? '#a5b4fc' : 'var(--text-secondary)',
                fontSize: 13, fontWeight: 600, cursor: 'pointer', transition: 'all 0.2s ease',
              }}
            >
              {p === 'anthropic' ? '🧠 Claude Haiku' : '⚡ Groq Llama 4'}
            </button>
          ))}
        </div>
        <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 8, lineHeight: 1.5 }}>
          {voiceProvider === 'anthropic' ? 'Claude Haiku — точнее, лучше с tools. Платный (~$0.001/запрос).' : 'Groq Llama 4 Scout — быстро, бесплатно. Хорошо работает с tools.'}
        </div>
      </div>

      {/* City selector */}
      <div style={{ background: 'var(--card-bg)', border: '1px solid var(--card-border)', borderRadius: 22, padding: '22px 24px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
          <MapPin size={18} color="#818cf8" />
          <span style={{ fontSize: 15, fontWeight: 600, color: 'var(--text-primary)' }}>Город</span>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8 }}>
          {CITIES.map(c => {
            const isActive = city === c.id
            return (
              <button key={c.id} onClick={() => onCityChange(c.id)} style={{
                padding: '12px 16px', borderRadius: 14, textAlign: 'left',
                background: isActive ? 'rgba(99,102,241,0.12)' : 'rgba(255,255,255,0.02)',
                border: `1px solid ${isActive ? 'rgba(129,140,248,0.25)' : 'rgba(255,255,255,0.05)'}`,
                color: isActive ? '#a5b4fc' : 'var(--text-secondary)',
                fontSize: 14, fontWeight: isActive ? 600 : 500,
                transition: 'all 0.25s ease',
                display: 'flex', alignItems: 'center', gap: 8,
              }}>
                {isActive && <Check size={14} />}
                {c.name}
              </button>
            )
          })}
        </div>
      </div>

      {/* Theme */}
      <div style={{ background: 'var(--card-bg)', border: '1px solid var(--card-border)', borderRadius: 22, padding: '22px 24px' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ fontSize: 18 }}>{theme === 'dark' ? '🌙' : '☀️'}</span>
            <span style={{ fontSize: 15, fontWeight: 600, color: 'var(--text-primary)' }}>Тема</span>
          </div>
          <div style={{ display: 'flex', gap: 6 }}>
            {[
              { id: 'dark', label: 'Тёмная' },
              { id: 'light', label: 'Светлая' },
            ].map(t => (
              <button key={t.id} onClick={() => onThemeChange(t.id)} style={{
                padding: '8px 16px', borderRadius: 12,
                background: theme === t.id ? 'rgba(99,102,241,0.12)' : 'rgba(255,255,255,0.02)',
                border: theme === t.id ? '1px solid rgba(129,140,248,0.25)' : '1px solid var(--card-border)',
                color: theme === t.id ? '#a5b4fc' : 'var(--text-secondary)',
                fontSize: 13, fontWeight: theme === t.id ? 600 : 500,
                transition: 'all 0.25s ease',
              }}>
                {t.label}
              </button>
            ))}
          </div>
        </div>
      </div>

      {/* PIN change */}
      <div style={{ background: 'var(--card-bg)', border: '1px solid var(--card-border)', borderRadius: 22, padding: '22px 24px' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <KeyRound size={18} color="#818cf8" />
            <span style={{ fontSize: 15, fontWeight: 600, color: 'var(--text-primary)' }}>PIN-код</span>
          </div>
          <button onClick={() => setShowPinChange(v => !v)} style={{
            padding: '8px 16px', borderRadius: 12,
            background: showPinChange ? 'rgba(255,255,255,0.04)' : 'rgba(99,102,241,0.1)',
            border: `1px solid ${showPinChange ? 'rgba(255,255,255,0.06)' : 'rgba(129,140,248,0.2)'}`,
            color: showPinChange ? 'var(--text-secondary)' : '#a5b4fc',
            fontSize: 13, fontWeight: 600,
          }}>
            {showPinChange ? 'Отмена' : 'Изменить'}
          </button>
        </div>

        {showPinChange && (
          <div style={{ marginTop: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
            <input
              type="password" inputMode="numeric" maxLength={8}
              value={oldPin} onChange={e => setOldPin(e.target.value.replace(/\D/g, ''))}
              placeholder="Старый PIN" style={inputStyle}
            />
            <input
              type="password" inputMode="numeric" maxLength={8}
              value={newPin} onChange={e => setNewPin(e.target.value.replace(/\D/g, ''))}
              placeholder="Новый PIN" style={inputStyle}
            />
            {pinMsg && (
              <div style={{
                fontSize: 13, padding: '10px 14px', borderRadius: 12, fontWeight: 500,
                background: pinMsg.ok ? 'rgba(52,211,153,0.08)' : 'rgba(239,68,68,0.08)',
                color: pinMsg.ok ? '#34d399' : '#f87171',
                display: 'flex', alignItems: 'center', gap: 8,
              }}>
                {pinMsg.ok ? <Check size={14} /> : <XIcon size={14} />} {pinMsg.text}
              </div>
            )}
            <button onClick={changePIN} disabled={pinSaving} style={{
              padding: '14px', borderRadius: 14,
              background: 'linear-gradient(135deg, rgba(99,102,241,0.3), rgba(139,92,246,0.2))',
              border: '1px solid rgba(129,140,248,0.3)',
              color: '#a5b4fc', fontSize: 14, fontWeight: 600,
            }}>
              {pinSaving ? 'Сохранение...' : 'Сохранить PIN'}
            </button>
          </div>
        )}
      </div>

      {/* Lock screen */}
      <button onClick={() => { const e = new CustomEvent('activate-screensaver'); window.dispatchEvent(e) }} style={{
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
        padding: '16px', borderRadius: 18,
        background: 'rgba(99,102,241,0.08)',
        border: '1px solid rgba(129,140,248,0.15)',
        color: '#a5b4fc', fontSize: 15, fontWeight: 600,
        transition: 'all 0.25s ease',
      }}>
        <Lock size={18} />
        Режим часов
      </button>

      {/* Logout */}
      <button onClick={onLogout} style={{
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
        padding: '16px', borderRadius: 18,
        background: 'rgba(239,68,68,0.06)',
        border: '1px solid rgba(239,68,68,0.15)',
        color: '#f87171', fontSize: 15, fontWeight: 600,
        transition: 'all 0.25s ease', marginTop: 8,
      }}>
        <LogOut size={18} />
        Выйти из аккаунта
      </button>

      {/* Info */}
      <div style={{ textAlign: 'center', padding: '16px 0', color: 'var(--text-tertiary)', fontSize: 12 }}>
        Smart Home Dashboard v1.0 · {currentCity.name}
      </div>
    </div>
  )
}

// ————— Tab animation variants —————
const tabVariants = {
  enter: { opacity: 0 },
  center: { opacity: 1 },
  exit: { opacity: 0 },
}

// ————— Main —————
function HomePageInner() {
  const [unlocked, setUnlocked] = useState<boolean | null>(null)
  const [tab, setTab] = useState<Tab>('home')
  const [activeRoom, setActiveRoom] = useState('living')
  const [weather, setWeather] = useState<WeatherData | null>(null)
  const [sensors, setSensors] = useState<SensorData | null>(null)
  const [haStates, setHaStates] = useState<HaStates>({})
  const [haConnected, setHaConnected] = useState(false)
  const [city, setCity] = useState(() => {
    if (typeof window !== 'undefined') return localStorage.getItem('tablet-city') || 'spb'
    return 'spb'
  })
  const [screensaverActive, setScreensaverActive] = useState(false)
  const [theme, setTheme] = useState(() => {
    if (typeof window !== 'undefined') return localStorage.getItem('tablet-theme') || 'dark'
    return 'dark'
  })
  const [nightShift, setNightShift] = useState(false)
  const idleTimer = useRef<ReturnType<typeof setTimeout> | null>(null)

  // Theme
  useEffect(() => {
    document.documentElement.className = theme
    localStorage.setItem('tablet-theme', theme)
  }, [theme])

  // Night-shift tint (22:00–06:00)
  useEffect(() => {
    const check = () => {
      const h = new Date().getHours()
      setNightShift(h >= 22 || h < 6)
    }
    check()
    const t = setInterval(check, 60_000)
    return () => clearInterval(t)
  }, [])

  // Auth check
  useEffect(() => {
    fetch('/api/auth')
      .then(r => r.json())
      .then(d => setUnlocked(d.authenticated))
      .catch(() => setUnlocked(false))
  }, [])

  // City change
  const handleCityChange = (id: string) => {
    setCity(id)
    localStorage.setItem('tablet-city', id)
  }

  // Weather
  useEffect(() => {
    if (!unlocked) return
    const c = CITIES.find(x => x.id === city) || CITIES[0]
    const load = async () => {
      try {
        const r = await fetch(`/api/weather?lat=${c.lat}&lon=${c.lon}`)
        const d = await r.json()
        if (d.temp && d.temp !== '—') setWeather(d)
      } catch {}
    }
    load()
    const t = setInterval(load, 600_000)
    return () => clearInterval(t)
  }, [unlocked, city])

  // HA
  const loadHA = useCallback(async () => {
    try {
      const r = await fetch('/api/ha')
      const d = await r.json()
      if (d.states) { setHaStates(d.states); setHaConnected(true) }
      if (d.sensors) setSensors(d.sensors)
    } catch { setHaConnected(false) }
  }, [])

  useEffect(() => {
    if (!unlocked) return
    loadHA()
    const t = setInterval(loadHA, 30_000)
    return () => clearInterval(t)
  }, [loadHA, unlocked])

  // Listen for manual screensaver activation
  useEffect(() => {
    const handler = () => setScreensaverActive(true)
    window.addEventListener('activate-screensaver', handler)
    return () => window.removeEventListener('activate-screensaver', handler)
  }, [])

  // Screensaver idle detection
  const resetIdle = useCallback(() => {
    if (screensaverActive) return // don't reset timer while screensaver is active
    if (idleTimer.current) clearTimeout(idleTimer.current)
    idleTimer.current = setTimeout(() => setScreensaverActive(true), 2 * 60 * 1000) // 2 min
  }, [screensaverActive])

  useEffect(() => {
    if (!unlocked) return
    const events = ['mousedown', 'mousemove', 'touchstart', 'keydown', 'scroll']
    events.forEach(e => window.addEventListener(e, resetIdle, { passive: true }))
    resetIdle()
    return () => {
      events.forEach(e => window.removeEventListener(e, resetIdle))
      if (idleTimer.current) clearTimeout(idleTimer.current)
    }
  }, [unlocked, resetIdle])

  // Swipe between tabs — edge-initiated horizontal drag
  const swipeStart = useRef<{ x: number; y: number; t: number; id: number } | null>(null)
  const handlePointerDown = (e: React.PointerEvent) => {
    // Only primary pointer / touch
    if (e.pointerType === 'mouse' && e.button !== 0) return
    swipeStart.current = { x: e.clientX, y: e.clientY, t: Date.now(), id: e.pointerId }
  }
  const handlePointerUp = (e: React.PointerEvent) => {
    const s = swipeStart.current
    swipeStart.current = null
    if (!s || s.id !== e.pointerId) return
    const dx = e.clientX - s.x
    const dy = e.clientY - s.y
    const dt = Date.now() - s.t
    // Conditions: fast enough, mostly horizontal, big enough
    const isHorizontal = Math.abs(dx) > Math.abs(dy) * 1.6
    const isLong = Math.abs(dx) > 90
    const isFast = dt < 600 || Math.abs(dx) > 160
    if (!(isHorizontal && isLong && isFast)) return
    // Don't steal swipe from elements that draggable-own (notes swipe-to-delete, weather modal, timer cards).
    const target = e.target as HTMLElement | null
    if (target?.closest('[data-swipe-ignore]')) return
    const idx = TAB_ORDER.indexOf(tab)
    if (idx < 0) return
    const nextIdx = dx < 0 ? idx + 1 : idx - 1
    if (nextIdx < 0 || nextIdx >= TAB_ORDER.length) return
    setTab(TAB_ORDER[nextIdx])
  }

  const devicesInRoom = DEVICES_BY_ROOM[activeRoom] || []
  const getDeviceState = (haKey?: string): boolean => {
    if (!haKey || !haStates[haKey]) return false
    return haStates[haKey].state === 'on'
  }
  const getDeviceExtra = (id: string): string | undefined => {
    if (id === 'air_purifier' && sensors) return `PM2.5: ${sensors.pm25}`
    return undefined
  }

  const handleLogout = async () => {
    await fetch('/api/auth', { method: 'DELETE' })
    window.location.reload()
  }

  if (unlocked === null) {
    return <div style={{ display: 'flex', height: '100dvh', alignItems: 'center', justifyContent: 'center', background: 'var(--bg)' }}><div className="bg-ambient" /></div>
  }
  if (!unlocked) {
    return <LockScreen onUnlock={() => setUnlocked(true)} />
  }

  return (
    <div className={getWeatherBgClass(weather?.desc || null)} style={{ display: 'flex', height: '100dvh', width: '100%', background: 'var(--bg)', overflow: 'hidden', position: 'relative' }}>
      <div className="bg-ambient"><div className="aurora-3" /></div>

      <AnimatePresence>
        {screensaverActive && (
          <Screensaver weather={weather} onDismiss={() => setScreensaverActive(false)} />
        )}
      </AnimatePresence>

      <VoiceOverlay />
      <VoiceController />
      <TimerWidget />

      <Sidebar active={tab} onChange={setTab} />

      {/* Night-shift warm tint overlay */}
      <div
        aria-hidden
        style={{
          position: 'fixed', inset: 0, zIndex: 150,
          background: 'rgba(255, 120, 40, 0.12)',
          mixBlendMode: 'multiply',
          pointerEvents: 'none',
          opacity: nightShift ? 1 : 0,
          transition: 'opacity 0.8s ease',
        }}
      />

      <main
        onPointerDown={handlePointerDown}
        onPointerUp={handlePointerUp}
        onPointerCancel={() => { swipeStart.current = null }}
        style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden', minWidth: 0, position: 'relative', zIndex: 1 }}
      >
        <TopBar sensors={sensors} haConnected={haConnected} />

        <AnimatePresence mode="sync" initial={false}>
          {tab === 'home' && (
            <motion.div key="home" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
              <HomeTab weather={weather} sensors={sensors} />
            </motion.div>
          )}

          {tab === 'devices' && (
            <motion.div key="devices" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
              <RoomTabs rooms={ROOMS} active={activeRoom} onChange={setActiveRoom} />
              <div style={{ flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch' as any, padding: '16px 24px 28px' }}>
                {devicesInRoom.length === 0 ? (
                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: 220, color: 'var(--text-secondary)', gap: 12 }}>
                    <div style={{ width: 64, height: 64, borderRadius: 20, background: 'rgba(255,255,255,0.04)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 28 }}>🏠</div>
                    <span style={{ fontSize: 15, fontWeight: 500 }}>Устройства не добавлены</span>
                  </div>
                ) : (
                  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14 }}>
                    {devicesInRoom.map(device => (
                      <DeviceCard key={device.id} id={device.id} name={device.name} icon={device.icon} entityId={device.entityId} domain={device.domain} initialState={getDeviceState(device.haKey)} isMock={device.isMock} extraInfo={getDeviceExtra(device.id)} />
                    ))}
                  </div>
                )}
              </div>
            </motion.div>
          )}

          {tab === 'calendar' && (
            <motion.div key="calendar" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
              <CalendarTab />
            </motion.div>
          )}

          {tab === 'notes' && (
            <motion.div key="notes" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
              <NotesTab />
            </motion.div>
          )}

          {tab === 'settings' && (
            <motion.div key="settings" variants={tabVariants} initial="enter" animate="center" exit="exit" transition={{ duration: 0.15 }} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
              <SettingsTab city={city} onCityChange={handleCityChange} onLogout={handleLogout} theme={theme} onThemeChange={setTheme} />
            </motion.div>
          )}
        </AnimatePresence>
      </main>
    </div>
  )
}

export default function HomePage() {
  return <HomePageInner />
}
