<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { useBackgroundRefresh } from '@/composables/useBackgroundRefresh'
import { useChatStore } from '@/stores/chat'
import ChatPanel from '@/components/ChatPanel.vue'
import WeatherCard from '@/components/WeatherCard.vue'
import BriefingSetupWizard from '@/components/BriefingSetupWizard.vue'
import {
  apiGet,
  apiPost,
  getBriefingConfig,
  getBriefingConversations,
  getBriefingToday,
  triggerBriefingSlot,
  postRssReaction,
  deleteRssReaction,
  getNewsItems,
  type BriefingConversation,
} from '@/api/client'
import type { NewsItem } from '@/types/news'

interface WeatherData {
  location: string
  fetched_at: string
  current_temp: number
  condition: string
  today_high: number | null
  today_low: number | null
  yesterday_high: number | null
  yesterday_low: number | null
  wind_unit?: string
  forecast: { day: string; condition: string; high: number; low: number; precip_probability: number | null; precip_mm: number | null; windspeed_max: number }[]
}

const chatStore = useChatStore()

// Setup wizard
const showWizard = ref(false)
const wizardChecked = ref(false)

async function checkSetup() {
  const config = await getBriefingConfig()
  if (!config.enabled) showWizard.value = true
  wizardChecked.value = true
}

async function onWizardDone() {
  showWizard.value = false
  await loadAll()
}

// Conversations list for the dropdown
const conversations = ref<BriefingConversation[]>([])
const selectedConvId = ref<number | null>(null)
const todayConvId = ref<number | null>(null)

const isToday = computed(() => selectedConvId.value === todayConvId.value)

// Weather panel (left column)
const weatherData = ref<WeatherData[]>([])
const tempUnit = ref<string>('C')

async function loadWeather() {
  try {
    const data = await apiGet<{ locations: WeatherData[]; temp_unit: string }>('/api/briefing/weather')
    weatherData.value = data.locations ?? []
    tempUnit.value = data.temp_unit ?? 'C'
  } catch { /* silent */ }
}

// News panel (right column)
const newsItems = ref<NewsItem[]>([])

async function loadNews() {
  try {
    const data = await getNewsItems({ days: 2, limit: 40 })
    newsItems.value = data.items
    // Seed reactions from API response
    for (const item of data.items) {
      if (reactions.value[item.id] === undefined) {
        reactions.value[item.id] = item.reaction
      }
    }
  } catch { /* silent */ }
}

async function loadAll() {
  const [convList, today] = await Promise.all([
    getBriefingConversations(),
    getBriefingToday().catch(() => null),
    loadWeather(),
    loadNews(),
  ])
  conversations.value = convList
  if (today) {
    todayConvId.value = today.id
    if (!convList.find((c) => c.id === today.id)) {
      conversations.value = [
        { id: today.id, title: today.title ?? 'Today', briefing_date: null, message_count: 0, created_at: new Date().toISOString() },
        ...convList,
      ]
    }
    selectedConvId.value = today.id
    await chatStore.fetchConversation(today.id)
  }
}

watch(selectedConvId, async (id) => {
  if (!id) return
  try {
    await chatStore.fetchConversation(id)
  } catch {
    // Historical conversation unavailable — do nothing
  }
})

async function discussArticle(item: NewsItem) {
  if (!todayConvId.value || chatStore.streaming) return
  if (!isToday.value) selectedConvId.value = todayConvId.value
  await nextTick(() => {
    document.querySelector('.briefing-center')?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
  })
  try {
    await apiPost<{ assistant_message_id: number }>(`/api/briefing/articles/${item.id}/discuss`, { conv_id: todayConvId.value })
  } catch {
    return
  }
  await chatStore.fetchConversation(todayConvId.value)
  await chatStore.reconnectIfGenerating(todayConvId.value)
}

// RSS reactions: map of rss_item_id -> 'up' | 'down' | null
const reactions = ref<Record<number, 'up' | 'down' | null>>({})

async function handleReaction(itemId: number, reaction: 'up' | 'down') {
  const current = reactions.value[itemId]
  reactions.value[itemId] = current === reaction ? null : reaction
  try {
    if (current === reaction) {
      await deleteRssReaction(itemId)
    } else {
      await postRssReaction(itemId, reaction)
    }
  } catch {
    reactions.value[itemId] = current ?? null
  }
}

function formatRelativeDate(iso: string | null): string {
  if (!iso) return ''
  const d = new Date(iso)
  const now = new Date()
  const diffH = (now.getTime() - d.getTime()) / 3_600_000
  if (diffH < 24) return `${Math.round(diffH)}h ago`
  if (diffH < 48) return 'Yesterday'
  return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
}

// Manual trigger
const triggering = ref(false)
async function triggerNow() {
  triggering.value = true
  try {
    await triggerBriefingSlot('compilation')
    // Guard: user may have navigated away during the long compilation
    if (_mounted) await loadAll()
  } finally {
    if (_mounted) triggering.value = false
  }
}

// Dropdown label
function convLabel(c: BriefingConversation): string {
  if (c.id === todayConvId.value) return 'Today'
  if (c.briefing_date) {
    const d = new Date(c.briefing_date)
    return d.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' })
  }
  return c.title || 'Briefing'
}

// ─── Background refresh (no-flicker) ─────────────────────────────────────────
async function _backgroundRefreshMessages() {
  try {
    const today = await getBriefingToday()
    if (!today) return
    if (_mounted && isToday.value && chatStore.currentConversation?.id === todayConvId.value) {
      await chatStore.fetchConversation(today.id)
    }
    await loadNews()
  } catch { /* silent — don't disturb the UI on network hiccup */ }
}

useBackgroundRefresh(
  _backgroundRefreshMessages,
  60_000,
  () => !chatStore.streaming && isToday.value && !!todayConvId.value,
)

let _mounted = true
onUnmounted(() => { _mounted = false })

onMounted(async () => {
  await checkSetup()
  if (!showWizard.value) await loadAll()
})
</script>

<template>
  <div class="briefing-root">
    <!-- Setup wizard overlay -->
    <BriefingSetupWizard v-if="wizardChecked && showWizard" @done="onWizardDone" />

    <!-- Main view -->
    <div class="briefing-shell" v-if="wizardChecked && !showWizard">
      <!-- Header spans all columns -->
      <header class="briefing-header">
        <div class="briefing-header-left">
          <h1 class="briefing-title">Briefing</h1>
          <span class="briefing-today-badge">{{ new Date().toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' }) }}</span>
        </div>
        <div class="briefing-header-right">
          <select v-if="conversations.length" v-model="selectedConvId" class="briefing-conv-select">
            <option v-for="c in conversations" :key="c.id" :value="c.id">{{ convLabel(c) }}</option>
          </select>
          <button
            class="btn-trigger"
            @click="triggerNow"
            :disabled="triggering"
            title="Manually trigger morning briefing now"
          >{{ triggering ? '…' : 'Refresh' }}</button>
        </div>
      </header>

      <!-- Left column: Weather -->
      <div class="briefing-left">
        <div class="panel-label">Weather</div>
        <template v-if="weatherData.length">
          <WeatherCard
            v-for="loc in weatherData"
            :key="(loc as WeatherData).location"
            :weather="loc"
            :temp-unit="tempUnit"
          />
        </template>
        <div v-else class="panel-empty">No weather configured</div>
      </div>

      <!-- Center column: Chat -->
      <div class="briefing-center">
        <ChatPanel
          variant="full"
          briefingMode
          :readOnly="!isToday"
          placeholder="Reply to your briefing…"
          class="briefing-chat-panel"
        />
      </div>

      <!-- Right column: News -->
      <div class="briefing-right">
        <div class="panel-label-row">
          <div class="panel-label">Today's News</div>
          <span v-if="newsItems.length" class="news-count">{{ newsItems.length }} items</span>
        </div>
        <div v-if="!newsItems.length" class="panel-empty">No articles in the last 2 days</div>
        <div
          v-for="item in newsItems"
          :key="item.id"
          class="news-card"
        >
          <div class="news-card-meta">
            <span class="news-source">{{ item.source }}</span>
            <span v-if="item.published_at" class="news-date">{{ formatRelativeDate(item.published_at) }}</span>
          </div>
          <a
            v-if="item.url"
            :href="item.url"
            target="_blank"
            rel="noopener noreferrer"
            class="news-title"
          >{{ item.title }}</a>
          <p v-else class="news-title news-title--plain">{{ item.title }}</p>
          <p v-if="item.snippet" class="news-snippet">{{ item.snippet }}</p>
          <div class="news-reactions">
            <button
              class="reaction-btn"
              :class="{ active: reactions[item.id] === 'up' }"
              @click="handleReaction(item.id, 'up')"
              title="Interested"
            >👍</button>
            <button
              class="reaction-btn"
              :class="{ active: reactions[item.id] === 'down' }"
              @click="handleReaction(item.id, 'down')"
              title="Not interested"
            >👎</button>
            <button
              v-if="isToday && todayConvId"
              class="reaction-btn discuss-btn"
              @click="discussArticle(item)"
              title="Discuss in briefing chat"
            >💬</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.briefing-root {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.briefing-shell {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  grid-template-rows: auto 1fr;
  height: 100%;
  min-height: 0;
}

.briefing-header {
  grid-column: 1 / -1;
  grid-row: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.25rem 1rem 1rem;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
  gap: 1rem;
  flex-wrap: wrap;
}

.briefing-header-left {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
}

.briefing-title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.3rem;
  font-weight: 700;
  margin: 0;
  color: var(--color-text);
}

.briefing-today-badge {
  font-size: 0.82rem;
  color: var(--color-text-muted);
}

.briefing-header-right {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.briefing-conv-select {
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-bg-card);
  color: var(--color-text);
  font-size: 0.82rem;
  cursor: pointer;
  font-family: inherit;
}

.btn-trigger {
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-bg-card);
  color: var(--color-text-muted);
  font-size: 0.8rem;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s;
  font-family: inherit;
}
.btn-trigger:hover:not(:disabled) {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.btn-trigger:disabled { opacity: 0.5; cursor: not-allowed; }

/* ─── Left column (Weather) ──────────────────────────────────────────────── */

.briefing-left {
  grid-column: 1;
  grid-row: 2;
  border-right: 1px solid var(--color-border);
  overflow-y: auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.briefing-left :deep(.weather-card) {
  margin-bottom: 0;
}

/* ─── Center column (Chat) ───────────────────────────────────────────────── */

.briefing-center {
  grid-column: 2;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.briefing-chat-panel {
  flex: 1;
  min-height: 0;
}

/* ─── Right column (News) ────────────────────────────────────────────────── */

.briefing-right {
  grid-column: 3;
  grid-row: 2;
  border-left: 1px solid var(--color-border);
  overflow-y: auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.panel-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-primary);
  flex-shrink: 0;
}

.panel-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
}

.news-count {
  font-size: 0.72rem;
  color: var(--color-text-muted);
}

.panel-empty {
  font-size: 0.82rem;
  color: var(--color-text-muted);
  padding: 0.5rem 0;
}

.news-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 0.65rem 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  flex-shrink: 0;
}

.news-card-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.news-source {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-primary);
}

.news-date {
  font-size: 0.72rem;
  color: var(--color-text-muted);
}

.news-title {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--color-text);
  line-height: 1.35;
  text-decoration: none;
  margin: 0;
}

a.news-title:hover { text-decoration: underline; color: var(--color-primary); }

.news-snippet {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  line-height: 1.45;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.news-reactions {
  display: flex;
  gap: 0.3rem;
  margin-top: 0.15rem;
}

.reaction-btn {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 0.1rem 0.35rem;
  cursor: pointer;
  font-size: 0.82rem;
  line-height: 1.4;
  opacity: 0.55;
  transition: opacity 0.15s, border-color 0.15s;
}

.reaction-btn:hover {
  opacity: 1;
  border-color: var(--color-primary);
}

.reaction-btn.active {
  opacity: 1;
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
}

/* ─── Responsive ─────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .briefing-shell {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto 1fr auto;
  }
  .briefing-header {
    grid-column: 1;
    grid-row: 1;
  }
  .briefing-left {
    grid-column: 1;
    grid-row: 2;
    border-right: none;
    border-bottom: 1px solid var(--color-border);
    max-height: 220px;
  }
  .briefing-center {
    grid-column: 1;
    grid-row: 3;
  }
  .briefing-right {
    grid-column: 1;
    grid-row: 4;
    border-left: none;
    border-top: 1px solid var(--color-border);
    max-height: 260px;
  }
}
</style>
