<template>
  <main class="home-view">
    <!-- Loading -->
    <div v-if="devicesStore.loading" class="home-view__loading" aria-live="polite">
      Loading…
    </div>

    <!-- Empty state -->
    <div v-else-if="devicesStore.devices.length === 0" class="home-view__empty">
      <div class="home-view__empty-card">
        <svg class="home-view__empty-icon" width="48" height="48" viewBox="0 0 24 24" fill="none"
             stroke="currentColor" stroke-width="1.5" aria-hidden="true">
          <rect x="3" y="3" width="18" height="18" rx="2"/>
          <circle cx="8.5" cy="8.5" r="1.5"/>
          <polyline points="21,15 16,10 5,21"/>
        </svg>
        <p class="home-view__empty-title">Set up your first frame</p>
        <p class="home-view__empty-sub">
          Power on your pictureFrame device and scan the QR code it displays to get started.
        </p>
      </div>
    </div>

    <!-- Single device — large card -->
    <div v-else-if="devicesStore.devices.length === 1" class="home-view__single">
      <FrameCard
        :deviceId="devicesStore.devices[0].id"
        :name="devicesStore.devices[0].name"
        size="large"
        :status="deviceStatus(devicesStore.devices[0])"
        :orientation="devicesStore.devices[0].orientation"
        :thumbnailUrl="previewUrl(devicesStore.devices[0])"
        :lastSync="lastSyncLabel(devicesStore.devices[0])"
        :nextSync="nextSyncLabel(devicesStore.devices[0])"
        @add-photo="onAddPhoto"
        @edit="onEdit"
      />
    </div>

    <!-- Multiple devices — swipeable carousel of large cards -->
    <template v-else>
      <div
        ref="carouselEl"
        class="home-view__carousel"
        role="region"
        aria-roledescription="carousel"
        aria-label="Frames"
        @scroll.passive="onCarouselScroll"
      >
        <div
          v-for="device in devicesStore.devices"
          :key="device.id"
          class="home-view__slide"
          role="group"
          :aria-roledescription="`Slide`"
          :aria-label="device.name"
        >
          <FrameCard
            :deviceId="device.id"
            :name="device.name"
            size="large"
            :status="deviceStatus(device)"
            :orientation="device.orientation"
            :thumbnailUrl="previewUrl(device)"
            :lastSync="lastSyncLabel(device)"
            :nextSync="nextSyncLabel(device)"
            @add-photo="onAddPhoto"
            @edit="onEdit"
          />
        </div>
      </div>
      <div class="home-view__dots" role="tablist" aria-label="Frame selector">
        <button
          v-for="(d, i) in devicesStore.devices"
          :key="d.id"
          type="button"
          role="tab"
          :class="['home-view__dot', { 'home-view__dot--active': i === activeSlide }]"
          :aria-label="`Go to ${d.name}`"
          :aria-selected="i === activeSlide"
          @click="goToSlide(i)"
        />
      </div>
    </template>
  </main>

  <!-- Frame settings sheet -->
  <BaseBottomSheet v-model="sheetOpen" label="Frame settings">
    <h2 class="home-view__sheet-title">Frame settings</h2>

    <div class="home-view__sheet-field">
      <BaseInput
        v-model="editName"
        label="Frame name"
        maxlength="100"
      />
    </div>

    <div class="home-view__sheet-field">
      <p class="home-view__sheet-label">Orientation</p>
      <OrientationPicker v-model="editOrientation" />
    </div>

    <div class="home-view__sheet-field">
      <p class="home-view__sheet-label">Update time</p>
      <div class="home-view__interval-grid">
        <button
          v-for="opt in WAKE_TIME_OPTIONS"
          :key="opt.hour"
          type="button"
          :class="['home-view__interval-chip', { 'home-view__interval-chip--on': editWakeHour === opt.hour }]"
          @click="editWakeHour = opt.hour"
        >{{ opt.label }}</button>
      </div>
      <select class="home-view__tz-select" v-model="editTimezone">
        <optgroup v-for="group in TIMEZONE_GROUPS" :key="group.label" :label="group.label">
          <option v-for="tz in group.zones" :key="tz.value" :value="tz.value">{{ tz.label }}</option>
        </optgroup>
      </select>
    </div>

    <BaseButton
      variant="primary"
      class="home-view__sheet-save"
      :disabled="saving"
      @click="saveSettings"
    >
      {{ saving ? 'Saving…' : 'Save' }}
    </BaseButton>
  </BaseBottomSheet>
</template>

<script setup lang="ts">
import { onMounted, ref, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useDevicesStore } from '@/stores/devices'
import { useUploadStore } from '@/stores/upload'
import type { Device } from '@/types'

// Sync interval for status comparisons. Devices configured with a daily wake
// hour use a 24h window; otherwise the rotation interval drives it.
function syncIntervalMs(device: Device): number {
  if (device.wakeHour !== null) return 24 * 60 * 60 * 1000
  return device.rotationIntervalMinutes * 60_000
}

function deviceStatus(device: Device): 'ok' | 'sync-fail' | 'offline' {
  if (!device.lastSeenAt) return 'offline'
  const elapsed = Date.now() - new Date(device.lastSeenAt).getTime()
  const interval = syncIntervalMs(device)
  if (elapsed <= interval)     return 'ok'
  if (elapsed <= 2 * interval) return 'sync-fail'
  return 'offline'
}

function lastSyncLabel(device: Device): string | null {
  if (!device.lastSeenAt) return null
  const ago = Date.now() - new Date(device.lastSeenAt).getTime()
  if (ago < 60_000)        return 'just now'
  if (ago < 3_600_000)     return `${Math.round(ago / 60_000)}m ago`
  if (ago < 86_400_000)    return `${Math.round(ago / 3_600_000)}h ago`
  const days = Math.round(ago / 86_400_000)
  if (days === 1) return 'yesterday'
  return `${days} days ago`
}

function formatHour(h: number): string {
  if (h === 0)  return '12 AM'
  if (h < 12)   return `${h} AM`
  if (h === 12) return '12 PM'
  return `${h - 12} PM`
}

function nextSyncLabel(device: Device): string | null {
  if (device.wakeHour !== null) {
    const fmt = new Intl.DateTimeFormat('en-US', {
      timeZone: device.timezone || 'UTC',
      hour: 'numeric',
      hour12: false,
    })
    const currentHour = parseInt(fmt.format(new Date()), 10)
    const tag = currentHour < device.wakeHour ? 'today' : 'tomorrow'
    return `next sync ~${formatHour(device.wakeHour)} ${tag}`
  }
  if (!device.lastSeenAt) return null
  const next = new Date(device.lastSeenAt).getTime() + device.rotationIntervalMinutes * 60_000
  const fromNow = next - Date.now()
  if (fromNow <= 0) return null
  if (fromNow < 60_000)     return 'next sync in <1m'
  if (fromNow < 3_600_000)  return `next sync in ${Math.round(fromNow / 60_000)}m`
  return `next sync in ${Math.round(fromNow / 3_600_000)}h`
}

function previewUrl(device: Device): string | undefined {
  const imageId = device.lockedImageId ?? device.currentImageId
  return imageId ? `/api/devices/${device.id}/preview?v=${imageId}` : undefined
}
import FrameCard from '@/components/FrameCard.vue'
import BaseBottomSheet from '@/components/BaseBottomSheet.vue'
import BaseButton from '@/components/BaseButton.vue'
import BaseInput from '@/components/BaseInput.vue'
import OrientationPicker from '@/components/OrientationPicker.vue'

const router       = useRouter()
const devicesStore = useDevicesStore()
const uploadStore  = useUploadStore()

onMounted(() => {
  devicesStore.fetchDevices()
})

// ── Multi-device carousel ─────────────────────────────────────────────────────

const carouselEl  = ref<HTMLElement | null>(null)
const activeSlide = ref(0)

function onCarouselScroll() {
  const el = carouselEl.value
  if (!el) return
  // Each slide is 100% of the carousel width — stride is clientWidth.
  activeSlide.value = Math.round(el.scrollLeft / el.clientWidth)
}

async function goToSlide(i: number) {
  await nextTick()
  const el = carouselEl.value
  if (!el) return
  el.scrollTo({ left: i * el.clientWidth, behavior: 'smooth' })
}

function onAddPhoto(deviceId: number) {
  // File picker must be triggered in the user-gesture context (the click handler)
  // before navigating, otherwise browsers block it as a popup.
  const input = document.createElement('input')
  input.type   = 'file'
  input.accept = 'image/jpeg,image/png,image/webp,image/gif'
  input.onchange = () => {
    const file = input.files?.[0]
    if (!file) return
    uploadStore.init(file, deviceId)
    router.push('/upload')
  }
  input.click()
}

// ── Settings sheet ────────────────────────────────────────────────────────────

const WAKE_TIME_OPTIONS = [
  { hour: 0,  label: '12 AM' },
  { hour: 2,  label: '2 AM'  },
  { hour: 4,  label: '4 AM'  },
  { hour: 6,  label: '6 AM'  },
  { hour: 8,  label: '8 AM'  },
  { hour: 10, label: '10 AM' },
  { hour: 12, label: '12 PM' },
  { hour: 18, label: '6 PM'  },
  { hour: 20, label: '8 PM'  },
  { hour: 22, label: '10 PM' },
]

const TIMEZONE_GROUPS = [
  { label: 'Americas', zones: [
    { value: 'America/New_York',    label: 'Eastern — New York, Toronto'       },
    { value: 'America/Chicago',     label: 'Central — Chicago, Mexico City'    },
    { value: 'America/Denver',      label: 'Mountain — Denver, Calgary'        },
    { value: 'America/Phoenix',     label: 'Mountain (no DST) — Phoenix'       },
    { value: 'America/Los_Angeles', label: 'Pacific — Los Angeles, Vancouver'  },
    { value: 'America/Anchorage',   label: 'Alaska — Anchorage'                },
    { value: 'Pacific/Honolulu',    label: 'Hawaii — Honolulu'                 },
    { value: 'America/Sao_Paulo',   label: 'Brasília — São Paulo'              },
    { value: 'America/Argentina/Buenos_Aires', label: 'Argentina — Buenos Aires' },
    { value: 'America/Bogota',      label: 'Colombia — Bogotá'                 },
  ]},
  { label: 'Europe', zones: [
    { value: 'Europe/London',    label: 'GMT/BST — London, Dublin'              },
    { value: 'Europe/Lisbon',    label: 'WET/WEST — Lisbon'                     },
    { value: 'Europe/Paris',     label: 'CET/CEST — Paris, Brussels, Amsterdam' },
    { value: 'Europe/Berlin',    label: 'CET/CEST — Berlin, Vienna, Zurich'     },
    { value: 'Europe/Stockholm', label: 'CET/CEST — Stockholm, Oslo, Copenhagen'},
    { value: 'Europe/Helsinki',  label: 'EET/EEST — Helsinki, Tallinn, Riga'    },
    { value: 'Europe/Warsaw',    label: 'CET/CEST — Warsaw, Prague, Budapest'   },
    { value: 'Europe/Rome',      label: 'CET/CEST — Rome, Madrid'               },
    { value: 'Europe/Athens',    label: 'EET/EEST — Athens, Bucharest'          },
    { value: 'Europe/Istanbul',  label: 'TRT — Istanbul'                        },
    { value: 'Europe/Moscow',    label: 'MSK — Moscow'                          },
  ]},
  { label: 'Asia & Pacific', zones: [
    { value: 'Asia/Dubai',        label: 'GST — Dubai, Abu Dhabi'               },
    { value: 'Asia/Karachi',      label: 'PKT — Karachi, Islamabad'             },
    { value: 'Asia/Kolkata',      label: 'IST — India'                          },
    { value: 'Asia/Dhaka',        label: 'BST — Dhaka, Bangladesh'              },
    { value: 'Asia/Bangkok',      label: 'ICT — Bangkok, Jakarta, Hanoi'        },
    { value: 'Asia/Singapore',    label: 'SGT — Singapore, Kuala Lumpur'        },
    { value: 'Asia/Shanghai',     label: 'CST — Beijing, Shanghai, Taipei'      },
    { value: 'Asia/Seoul',        label: 'KST — Seoul'                          },
    { value: 'Asia/Tokyo',        label: 'JST — Tokyo'                          },
    { value: 'Australia/Sydney',  label: 'AEDT/AEST — Sydney, Melbourne'        },
    { value: 'Australia/Brisbane',label: 'AEST (no DST) — Brisbane'             },
    { value: 'Australia/Perth',   label: 'AWST — Perth'                         },
    { value: 'Pacific/Auckland',  label: 'NZDT/NZST — Auckland'                 },
  ]},
  { label: 'Africa & Middle East', zones: [
    { value: 'Africa/Cairo',        label: 'EET — Cairo'               },
    { value: 'Africa/Nairobi',      label: 'EAT — Nairobi, East Africa'},
    { value: 'Africa/Johannesburg', label: 'SAST — Johannesburg'       },
    { value: 'Africa/Lagos',        label: 'WAT — Lagos, West Africa'  },
  ]},
  { label: 'UTC', zones: [
    { value: 'UTC', label: 'UTC — Coordinated Universal Time' },
  ]},
]

const sheetOpen = ref(false)
const saving = ref(false)
const editingDevice = ref<Device | null>(null)
const editName = ref('')
const editOrientation = ref<Device['orientation']>('landscape')
const editWakeHour = ref<number>(4)
const editTimezone = ref('UTC')

function onEdit(deviceId: number) {
  const device = devicesStore.devices.find(d => d.id === deviceId)
  if (!device) return
  editingDevice.value = device
  editName.value = device.name
  editOrientation.value = device.orientation
  editWakeHour.value = device.wakeHour ?? 4
  editTimezone.value = device.timezone ?? 'UTC'
  sheetOpen.value = true
}

async function saveSettings() {
  if (!editingDevice.value) return
  saving.value = true
  try {
    await devicesStore.updateDevice(editingDevice.value.id, {
      name: editName.value.trim() || editingDevice.value.name,
      orientation: editOrientation.value,
      wakeHour: editWakeHour.value,
      timezone: editTimezone.value,
    })
    sheetOpen.value = false
  } finally {
    saving.value = false
  }
}
</script>

<style scoped lang="scss">
.home-view {
  flex: 1;
  padding: var(--space-4) var(--space-4) calc(var(--bottom-nav-height) + var(--space-4));
  display: flex;
  flex-direction: column;
  gap: var(--space-3);

  &__loading {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    padding: var(--space-4) 0;
    text-align: center;
  }

  &__empty {
    display: flex;
    justify-content: center;
    padding-top: var(--space-6);
  }

  &__empty-card {
    background: var(--color-surface);
    border: 2px dashed var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-6) var(--space-5);
    text-align: center;
    max-width: 320px;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
  }

  &__empty-icon {
    color: var(--color-text-muted);
    opacity: 0.5;
  }

  &__empty-title {
    font-size: var(--text-md);
    font-weight: 700;
  }

  &__empty-sub {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    line-height: 1.5;
  }

  &__single {
    flex: 1;
    display: flex;
    flex-direction: column;
  }

  // Carousel: full-bleed horizontal scroll-snap. The container ignores the
  // page's side padding so cards reach edge-to-edge; each slide pads itself
  // back in so the card visually aligns with the rest of the page.
  &__carousel {
    flex: 1;
    min-height: 0;
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    margin: 0 calc(-1 * var(--space-4));

    &::-webkit-scrollbar { display: none; }
  }

  &__slide {
    flex: 0 0 100%;
    box-sizing: border-box;
    padding: 0 var(--space-4);
    scroll-snap-align: start;
    scroll-snap-stop: always;
    display: flex;
    flex-direction: column;
  }

  &__dots {
    display: flex;
    justify-content: center;
    gap: var(--space-2);
    padding-top: var(--space-3);
  }

  &__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: none;
    padding: 0;
    background: var(--color-border);
    cursor: pointer;
    transition: background var(--duration-fast), transform var(--duration-fast);

    &--active {
      background: var(--color-primary);
      transform: scale(1.25);
    }
  }

  &__sheet-title {
    font-size: var(--text-md);
    font-weight: 700;
    margin-bottom: var(--space-4);
  }

  &__sheet-field {
    margin-bottom: var(--space-4);
  }

  &__sheet-label {
    display: block;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-text-muted);
    margin-bottom: var(--space-2);
  }

  &__interval-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  &__tz-select {
    width: 100%;
    margin-top: var(--space-3);
    min-height: var(--touch-min);
    padding: 0 var(--space-3);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--text-sm);
    font-family: inherit;
    cursor: pointer;
    appearance: auto;

    &:focus {
      outline: 2px solid var(--color-primary);
      outline-offset: 2px;
    }
  }

  &__interval-chip {
    padding: 6px 14px;
    border-radius: 999px;
    border: 1.5px solid var(--color-border);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    background: transparent;
    color: var(--color-text-muted);
    transition: all var(--duration-fast);
    min-height: var(--touch-min);

    &--on {
      background: var(--color-primary);
      border-color: var(--color-primary);
      color: var(--color-primary-fg);
    }
  }

  &__sheet-save {
    width: 100%;
    margin-top: var(--space-2);
  }
}
</style>
