<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import { invoke } from '@tauri-apps/api/core'
import TitleBar from './components/TitleBar.vue'
import NavRail from './components/NavRail.vue'
import ToastNotification from './components/ToastNotification.vue'
import { useSettingsStore } from './stores/settings'
import { useToastStore } from './stores/toast'
import { useTimerStore } from './stores/timer'
import { useRecurringStore } from './stores/recurring'
import { loadAndApplyTimerFont } from './utils/fonts'
import { loadAndApplyUIFont } from './utils/uiFonts'
import { useAnnouncer } from './composables/useAnnouncer'
import { audioEngine, DEFAULT_EVENTS } from './utils/audio'
import type { SoundEvent } from './utils/audio'
import TourOverlay from './components/TourOverlay.vue'
import RecurringPromptDialog from './components/RecurringPromptDialog.vue'
import TimerSaveDialog from './components/TimerSaveDialog.vue'
import QuickEntryDialog from './components/QuickEntryDialog.vue'
import KeyboardShortcutsDialog from './components/KeyboardShortcutsDialog.vue'
import GlobalSearchDialog from './components/GlobalSearchDialog.vue'
import { useOnboardingStore } from './stores/onboarding'
import { useProjectsStore } from './stores/projects'
import { useInvoicesStore } from './stores/invoices'

const settingsStore = useSettingsStore()
const recurringStore = useRecurringStore()
const timerStore = useTimerStore()
const { announcement } = useAnnouncer()
const showQuickEntry = ref(false)
const showShortcuts = ref(false)
const showSearch = ref(false)

function getProjectName(projectId?: number): string {
  if (!projectId) return ''
  const projectsStore = useProjectsStore()
  return projectsStore.projects.find(p => p.id === projectId)?.name || ''
}

function getProjectColor(projectId?: number): string {
  if (!projectId) return '#6B7280'
  const projectsStore = useProjectsStore()
  return projectsStore.projects.find(p => p.id === projectId)?.color || '#6B7280'
}

let shortcutRegistering = false
async function registerShortcuts() {
  if (shortcutRegistering) return
  shortcutRegistering = true
  try {
    const { unregisterAll, register } = await import('@tauri-apps/plugin-global-shortcut')
    await unregisterAll()
    const toggleKey = settingsStore.settings.shortcut_toggle_timer || 'CmdOrCtrl+Shift+T'
    const showKey = settingsStore.settings.shortcut_show_app || 'CmdOrCtrl+Shift+Z'

    await register(toggleKey, () => {
      const timerStore = useTimerStore()
      if (timerStore.isStopped) {
        if (timerStore.selectedProjectId) timerStore.start()
      } else {
        timerStore.stop()
      }
    })

    await register(showKey, async () => {
      const { getCurrentWindow } = await import('@tauri-apps/api/window')
      const win = getCurrentWindow()
      await win.show()
      await win.setFocus()
    })

    const quickEntryKey = settingsStore.settings.shortcut_quick_entry || 'CmdOrCtrl+Shift+N'
    await register(quickEntryKey, async () => {
      const { getCurrentWindow } = await import('@tauri-apps/api/window')
      const win = getCurrentWindow()
      await win.show()
      await win.setFocus()
      showQuickEntry.value = true
    })
  } catch (e) {
    console.error('Failed to register shortcuts:', e)
  } finally {
    shortcutRegistering = false
  }
}

function applyTheme() {
  const el = document.documentElement
  const mode = settingsStore.settings.theme_mode || 'dark'
  const accent = settingsStore.settings.accent_color || 'amber'

  if (mode === 'system') {
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
    el.setAttribute('data-theme', prefersDark ? 'dark' : 'light')
  } else {
    el.setAttribute('data-theme', mode)
  }
  el.setAttribute('data-accent', accent)
}

function daysDiff(a: string, b: string): number {
  const ms = new Date(b).getTime() - new Date(a).getTime()
  return Math.floor(ms / 86400000)
}

async function checkScheduledBackup() {
  const s = settingsStore.settings
  if (s.auto_backup !== 'true' || !s.backup_path) return
  const lastBackup = s.auto_backup_last || ''
  const frequency = s.auto_backup_frequency || 'daily'
  const retention = parseInt(s.auto_backup_retention || '7')
  const today = new Date().toISOString().split('T')[0]

  const isDue = !lastBackup || (frequency === 'daily' && lastBackup < today) ||
    (frequency === 'weekly' && daysDiff(lastBackup, today) >= 7)
  if (!isDue) return

  try {
    await invoke('auto_backup', { backupDir: s.backup_path })
    await settingsStore.updateSetting('auto_backup_last', today)
    const toastStore = useToastStore()
    const files = await invoke<any[]>('list_backup_files', { backupDir: s.backup_path })
    if (files.length > retention) {
      for (const old of files.slice(retention)) {
        await invoke('delete_backup_file', { path: old.path })
      }
    }
    toastStore.success('Auto-backup completed')
  } catch (e) {
    console.error('Scheduled backup failed:', e)
  }
}

function applyMotion() {
  const setting = settingsStore.settings.reduce_motion || 'system'
  const el = document.documentElement
  if (setting === 'on') {
    el.classList.add('reduce-motion')
  } else if (setting === 'off') {
    el.classList.remove('reduce-motion')
  } else {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      el.classList.add('reduce-motion')
    } else {
      el.classList.remove('reduce-motion')
    }
  }
}

onMounted(async () => {
  await settingsStore.fetchSettings()

  const onboardingStore = useOnboardingStore()
  await onboardingStore.load()

  await timerStore.restoreState()

  const zoom = parseInt(settingsStore.settings.ui_zoom) || 100
  const app = document.getElementById('app')
  if (app) {
    (app.style as any).zoom = `${zoom}%`
  }
  applyTheme()
  applyMotion()
  loadAndApplyTimerFont(settingsStore.settings.timer_font || 'JetBrains Mono')

  const dyslexiaMode = settingsStore.settings.dyslexia_mode === 'true'
  if (dyslexiaMode) {
    loadAndApplyUIFont('OpenDyslexic')
  } else {
    const uiFont = settingsStore.settings.ui_font
    if (uiFont && uiFont !== 'Inter') {
      loadAndApplyUIFont(uiFont)
    }
  }

  // Load audio settings
  const soundEnabled = settingsStore.settings.sound_enabled === 'true'
  const soundMode = (settingsStore.settings.sound_mode || 'synthesized') as 'synthesized' | 'system' | 'custom'
  const soundVolume = parseInt(settingsStore.settings.sound_volume) || 70
  let soundEvents: Record<string, boolean> = {}
  try {
    soundEvents = JSON.parse(settingsStore.settings.sound_events || '{}')
  } catch { /* use defaults */ }

  audioEngine.updateSettings({
    enabled: soundEnabled,
    mode: soundMode,
    volume: soundVolume,
    events: { ...DEFAULT_EVENTS, ...soundEvents } as Record<SoundEvent, boolean>,
  })

  // Initialize persistent notifications setting
  const toastStore = useToastStore()
  toastStore.setPersistentNotifications(settingsStore.settings.persistent_notifications === 'true')

  await recurringStore.fetchEntries()
  recurringStore.checkRecurrences()
  setInterval(() => recurringStore.checkRecurrences(), 60000)
  setInterval(() => onboardingStore.detectCompletions(), 5 * 60000)

  // Background calendar sync
  async function syncCalendars() {
    try {
      const sources = await invoke<any[]>('get_calendar_sources')
      for (const source of sources) {
        if (source.source_type === 'url' && source.enabled && source.url) {
          try {
            const resp = await fetch(source.url)
            if (resp.ok) {
              const content = await resp.text()
              await invoke('import_ics_file', { sourceId: source.id, content })
            }
          } catch (e) {
            console.error('Calendar sync failed for', source.name, e)
          }
        }
      }
    } catch (e) {
      console.error('Failed to sync calendars:', e)
    }
  }

  syncCalendars()
  setInterval(syncCalendars, 30 * 60000)

  const invoicesStore = useInvoicesStore()
  await invoicesStore.fetchInvoices()
  const overdueCount = await invoicesStore.checkOverdue()
  if (overdueCount > 0) {
    const toastStore = useToastStore()
    toastStore.info(`${overdueCount} invoice(s) now overdue`)
  }

  await checkScheduledBackup()

  // End-of-day reminder and weekly summary checks
  const reminderState = { eodShownToday: '', weeklySummaryShownWeek: '' }

  async function checkReminders() {
    const now = new Date()
    const todayStr = now.toISOString().split('T')[0]
    const currentTime = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`

    // End-of-day reminder
    if (settingsStore.settings.eod_reminder_enabled === 'true' && reminderState.eodShownToday !== todayStr) {
      const reminderTime = settingsStore.settings.eod_reminder_time || '17:00'
      if (currentTime >= reminderTime) {
        reminderState.eodShownToday = todayStr
        try {
          const entries = await invoke<any[]>('get_time_entries', { startDate: todayStr, endDate: todayStr })
          const totalSeconds = entries.reduce((sum: number, e: any) => sum + (e.duration || 0), 0)
          const totalHours = totalSeconds / 3600
          const goalHours = parseFloat(settingsStore.settings.daily_goal_hours) || 8
          if (totalHours < goalHours) {
            const remaining = (goalHours - totalHours).toFixed(1)
            const toastStore = useToastStore()
            toastStore.info(`End of day: ${totalHours.toFixed(1)}h logged today, ${remaining}h remaining to reach your ${goalHours}h goal`)
          }
        } catch {
          // ignore
        }
      }
    }

    // Weekly summary (Monday check)
    if (settingsStore.settings.weekly_summary_enabled === 'true' && now.getDay() === 1) {
      const weekId = todayStr
      if (reminderState.weeklySummaryShownWeek !== weekId && now.getHours() >= 9) {
        reminderState.weeklySummaryShownWeek = weekId
        try {
          const lastMonday = new Date(now)
          lastMonday.setDate(now.getDate() - 7)
          const lastSunday = new Date(now)
          lastSunday.setDate(now.getDate() - 1)
          const entries = await invoke<any[]>('get_time_entries', {
            startDate: lastMonday.toISOString().split('T')[0],
            endDate: lastSunday.toISOString().split('T')[0],
          })
          const totalSeconds = entries.reduce((sum: number, e: any) => sum + (e.duration || 0), 0)
          const totalHours = totalSeconds / 3600
          const goalHours = parseFloat(settingsStore.settings.weekly_goal_hours) || 40
          const toastStore = useToastStore()
          toastStore.info(`Weekly summary: ${totalHours.toFixed(1)}h logged last week (goal: ${goalHours}h)`)
        } catch {
          // ignore
        }
      }
    }
  }

  checkReminders()
  setInterval(checkReminders, 60000)

  registerShortcuts()

  document.addEventListener('keydown', (e) => {
    if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
      e.preventDefault()
      showSearch.value = true
      return
    }
    if (e.key === '?' && !e.ctrlKey && !e.metaKey && !e.altKey) {
      const tag = (e.target as HTMLElement)?.tagName
      if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return
      if ((e.target as HTMLElement)?.isContentEditable) return
      e.preventDefault()
      showShortcuts.value = !showShortcuts.value
    }
  })

  // Handle window close - backup and optionally hide to tray
  try {
    const { getCurrentWindow } = await import('@tauri-apps/api/window')
    const win = getCurrentWindow()
    win.onCloseRequested(async (event) => {
      if (settingsStore.settings.auto_backup === 'true' && settingsStore.settings.backup_path) {
        try {
          await invoke('auto_backup', { backupDir: settingsStore.settings.backup_path })
        } catch (e) {
          console.error('Auto-backup failed:', e)
        }
      }
      if (settingsStore.settings.close_to_tray === 'true') {
        event.preventDefault()
        await win.hide()
      }
    })
  } catch (e) {
    console.error('Failed to register close handler:', e)
  }

  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
    if (settingsStore.settings.theme_mode === 'system') applyTheme()
  })

  window.matchMedia('(prefers-reduced-motion: reduce)').addEventListener('change', () => {
    if (settingsStore.settings.reduce_motion === 'system' || !settingsStore.settings.reduce_motion) {
      applyMotion()
    }
  })
})

watch(() => [settingsStore.settings.theme_mode, settingsStore.settings.accent_color], () => {
  applyTheme()
})

watch(() => settingsStore.settings.reduce_motion, () => {
  applyMotion()
})

watch(() => settingsStore.settings.timer_font, (newFont) => {
  if (newFont) loadAndApplyTimerFont(newFont)
})

watch(() => settingsStore.settings.dyslexia_mode, (val) => {
  if (val === 'true') {
    loadAndApplyUIFont('OpenDyslexic')
  } else {
    const uiFont = settingsStore.settings.ui_font || 'Inter'
    loadAndApplyUIFont(uiFont)
  }
})

watch(() => settingsStore.settings.ui_font, (newFont) => {
  if (settingsStore.settings.dyslexia_mode !== 'true' && newFont) {
    loadAndApplyUIFont(newFont)
  }
})

watch(() => [settingsStore.settings.shortcut_toggle_timer, settingsStore.settings.shortcut_show_app, settingsStore.settings.shortcut_quick_entry], () => {
  registerShortcuts()
})

watch(() => settingsStore.settings.sound_enabled, (val) => {
  audioEngine.updateSettings({ enabled: val === 'true' })
})

watch(() => settingsStore.settings.sound_mode, (val) => {
  if (val) audioEngine.updateSettings({ mode: val as 'synthesized' | 'system' | 'custom' })
})

watch(() => settingsStore.settings.sound_volume, (val) => {
  audioEngine.updateSettings({ volume: parseInt(val) || 70 })
})

watch(() => settingsStore.settings.sound_events, (val) => {
  if (val) {
    try {
      const parsed = JSON.parse(val)
      audioEngine.updateSettings({ events: { ...DEFAULT_EVENTS, ...parsed } as Record<SoundEvent, boolean> })
    } catch { /* ignore parse errors */ }
  }
})

watch(() => settingsStore.settings.persistent_notifications, (val) => {
  const toastStore = useToastStore()
  toastStore.setPersistentNotifications(val === 'true')
})
</script>

<template>
  <a href="#main-content" class="sr-only sr-only-focusable fixed top-0 left-0 z-[200] bg-accent text-white px-4 py-2 rounded-br-lg">
    Skip to main content
  </a>
  <div class="h-full w-full flex flex-col bg-bg-base">
    <TitleBar />
    <div class="flex-1 flex overflow-hidden">
      <NavRail />
      <main id="main-content" class="flex-1 overflow-auto" tabindex="-1">
        <router-view v-slot="{ Component }">
          <Transition name="page" mode="out-in" :duration="{ enter: 250, leave: 150 }">
            <component :is="Component" :key="$route.path" />
          </Transition>
        </router-view>
      </main>
    </div>
  </div>
  <ToastNotification />
  <RecurringPromptDialog
    :show="recurringStore.pendingPrompt !== null"
    :project-name="getProjectName(recurringStore.pendingPrompt?.project_id)"
    :project-color="getProjectColor(recurringStore.pendingPrompt?.project_id)"
    :task-name="''"
    :description="recurringStore.pendingPrompt?.description || ''"
    :duration="recurringStore.pendingPrompt?.duration || 0"
    :time-of-day="recurringStore.pendingPrompt?.time_of_day || ''"
    @confirm="recurringStore.confirmPrompt()"
    @snooze="recurringStore.snoozePrompt()"
    @skip="recurringStore.skipPrompt()"
  />
  <TimerSaveDialog
    :show="timerStore.showSaveDialog"
    :elapsed-seconds="timerStore.pendingStopDuration"
    :mode="timerStore.saveDialogMode"
    @save="timerStore.handleSaveDialogSave"
    @discard="timerStore.handleSaveDialogDiscard"
    @cancel="timerStore.handleSaveDialogCancel"
  />
  <QuickEntryDialog
    :show="showQuickEntry"
    @close="showQuickEntry = false"
    @saved="showQuickEntry = false"
  />
  <div id="route-announcer" class="sr-only" aria-live="polite" aria-atomic="true"></div>
  <div id="announcer" class="sr-only" aria-live="assertive" aria-atomic="true">{{ announcement }}</div>
  <TourOverlay />
  <KeyboardShortcutsDialog :show="showShortcuts" @close="showShortcuts = false" />
  <GlobalSearchDialog :show="showSearch" @close="showSearch = false" />
</template>
