<template>
  <v-container fluid class="py-6">
    <div class="fc-subs__bar">
      <v-btn color="accent" prepend-icon="mdi-plus" @click="openAddSource(null)">
        Add subscription
      </v-btn>
      <v-btn variant="outlined" prepend-icon="mdi-account-plus" @click="showArtistDialog = true">
        New artist
      </v-btn>
      <v-spacer />
      <v-text-field
        v-model="search"
        density="compact" variant="outlined" hide-details clearable
        prepend-inner-icon="mdi-magnify"
        placeholder="Search subscriptions"
        style="max-width: 320px"
      />
    </div>

    <v-alert v-if="store.error" type="error" variant="tonal" closable class="mt-4">
      {{ String(store.error) }}
    </v-alert>

    <div v-if="store.loading && groups.length === 0" class="fc-subs__loading">
      <v-progress-circular indeterminate color="accent" size="36" />
    </div>

    <div v-else-if="filteredGroups.length === 0" class="fc-subs__empty">
      <p v-if="groups.length === 0">No subscriptions yet. Add your first artist.</p>
      <p v-else>No subscriptions match "{{ search }}".</p>
    </div>

    <v-card v-else class="fc-subs__card" variant="outlined">
      <v-data-table
        :headers="headers"
        :items="filteredGroups"
        item-value="key"
        v-model:expanded="expanded"
        :items-per-page="50"
        :items-per-page-options="ITEMS_PER_PAGE_OPTIONS"
        density="comfortable"
        hover
        show-expand
        @click:row="onRowClick"
      >
        <template #item.name="{ item }">
          <span class="fc-subs__name">{{ item.artist.name }}</span>
        </template>

        <template #item.sources_count="{ item }">
          <v-chip size="x-small" variant="tonal" label>
            {{ item.sources.length }} source{{ item.sources.length === 1 ? '' : 's' }}
          </v-chip>
        </template>

        <template #item.health="{ item }">
          <SourceHealthDot
            v-if="item.worstSource"
            :source="item.worstSource"
            :warning-threshold="failureThreshold"
          />
          <span v-else class="fc-subs__zero">—</span>
        </template>

        <template #item.last_activity="{ item }">
          <span class="fc-subs__when">
            {{ formatRelative(item.lastActivity) }}
          </span>
        </template>

        <template #item.actions="{ item }">
          <v-btn
            icon size="small" variant="text"
            :loading="anyChecking(item.sources)"
            @click.stop="checkAll(item)"
          >
            <v-icon>mdi-refresh</v-icon>
            <v-tooltip activator="parent" location="top">Check all sources</v-tooltip>
          </v-btn>
          <v-btn
            icon size="small" variant="text"
            @click.stop="openAddSource(item.artist)"
          >
            <v-icon>mdi-plus</v-icon>
            <v-tooltip activator="parent" location="top">Add source</v-tooltip>
          </v-btn>
          <v-btn
            icon size="small" variant="text"
            :to="`/posts?artist_id=${item.artist.id}`"
            @click.stop
          >
            <v-icon>mdi-rss</v-icon>
            <v-tooltip activator="parent" location="top">View posts</v-tooltip>
          </v-btn>
          <v-btn
            icon size="small" variant="text"
            :to="`/artist/${item.artist.slug}`"
            @click.stop
          >
            <v-icon>mdi-account</v-icon>
            <v-tooltip activator="parent" location="top">Open artist page</v-tooltip>
          </v-btn>
        </template>

        <template #expanded-row="{ columns, item }">
          <tr class="fc-subs__sources-row">
            <td :colspan="columns.length" class="fc-subs__sources-cell">
              <v-table density="compact" class="fc-subs__sources-table">
                <thead>
                  <tr>
                    <th></th>
                    <th>Platform</th>
                    <th>URL</th>
                    <th>Enabled</th>
                    <th>Last check</th>
                    <th>Next check</th>
                    <th>Errors</th>
                    <th class="text-right">Actions</th>
                  </tr>
                </thead>
                <tbody>
                  <SourceRow
                    v-for="s in item.sources" :key="s.id" :source="s"
                    :checking="store.checkingIds.has(s.id)"
                    :warning-threshold="failureThreshold"
                    @edit="openEditSource"
                    @remove="removeSource"
                    @toggle="toggleSourceEnabled"
                    @check="onCheck"
                  />
                  <tr v-if="item.sources.length === 0">
                    <td colspan="8" class="fc-subs__sources-empty">
                      No sources yet. Click + to add one.
                    </td>
                  </tr>
                </tbody>
              </v-table>
            </td>
          </tr>
        </template>
      </v-data-table>
    </v-card>

    <SourceFormDialog
      v-model="showSourceDialog"
      :source="editingSource"
      :initial-artist="editingArtist"
      @saved="onSourceSaved"
    />
    <ArtistCreateDialog v-model="showArtistDialog" @created="onArtistCreated" />
  </v-container>
</template>

<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useSourcesStore } from '../stores/sources.js'
import { usePlatformsStore } from '../stores/platforms.js'
import { useImportStore } from '../stores/import.js'
import SourceRow from '../components/subscriptions/SourceRow.vue'
import SourceHealthDot from '../components/subscriptions/SourceHealthDot.vue'
import SourceFormDialog from '../components/subscriptions/SourceFormDialog.vue'
import ArtistCreateDialog from '../components/subscriptions/ArtistCreateDialog.vue'

const ITEMS_PER_PAGE_OPTIONS = [
  { value: 25, title: '25' },
  { value: 50, title: '50' },
  { value: 100, title: '100' },
  { value: -1, title: 'All' },
]

const route = useRoute()
const router = useRouter()
const store = useSourcesStore()
const platformsStore = usePlatformsStore()
const importStore = useImportStore()

const search = ref('')
const expanded = ref([])
const showSourceDialog = ref(false)
const editingSource = ref(null)
const editingArtist = ref(null)
const showArtistDialog = ref(false)

const artistFilter = computed(() => {
  const raw = route.query.artist_id
  return raw == null ? null : Number(raw)
})

const failureThreshold = computed(() =>
  importStore.settings?.download_failure_warning_threshold ?? 5
)

async function refresh() {
  await store.loadAll()
  await platformsStore.loadAll()
  if (!importStore.settings) await importStore.loadSettings()
}

onMounted(() => {
  refresh()
  if (artistFilter.value != null) {
    // Pre-expand the row that the deep-link refers to.
    expanded.value = [`artist-${artistFilter.value}`]
  }
})
watch(() => route.query.artist_id, refresh)

const headers = [
  { title: 'Subscription', key: 'name',          sortable: true,  align: 'start' },
  { title: 'Sources',      key: 'sources_count', sortable: true,  align: 'start', width: 110 },
  { title: 'Health',       key: 'health',        sortable: false, align: 'start', width: 80 },
  { title: 'Last activity',key: 'last_activity', sortable: true,  align: 'start', width: 140 },
  { title: 'Actions',      key: 'actions',       sortable: false, align: 'end',   width: 200 },
]

const groups = computed(() => {
  const all = store.sourcesByArtistGrouped()
  return all.map(g => {
    const worstSource = pickWorstSource(g.sources, failureThreshold.value)
    const lastActivity = pickLastActivity(g.sources)
    return {
      key: `artist-${g.artist.id}`,
      artist: g.artist,
      sources: g.sources,
      sources_count: g.sources.length,
      worstSource,
      lastActivity,
      name: g.artist.name,                 // for sortable column
      last_activity: lastActivity ?? '',   // for sortable column
    }
  })
})

const filteredGroups = computed(() => {
  let arr = groups.value
  if (artistFilter.value != null) {
    arr = arr.filter(g => g.artist.id === artistFilter.value)
  }
  const q = search.value?.trim().toLowerCase()
  if (q) {
    arr = arr.filter(g =>
      g.artist.name.toLowerCase().includes(q)
      || g.sources.some(s => (s.url || '').toLowerCase().includes(q)
                          || (s.platform || '').toLowerCase().includes(q))
    )
  }
  return arr
})

function pickLastActivity(sources) {
  let max = null
  for (const s of sources) {
    if (s.last_checked_at && (!max || s.last_checked_at > max)) max = s.last_checked_at
  }
  return max
}

function pickWorstSource(sources, threshold) {
  // Health order (worst → best): critical, warning, healthy, unchecked.
  // Picks the source with the worst level so the row's dot reflects the
  // worst-case state. Within a level, the first is fine.
  if (!sources || sources.length === 0) return null
  function level(s) {
    if (!s.last_checked_at) return 0           // unchecked
    const f = s.consecutive_failures || 0
    if (f === 0) return 1                       // healthy
    if (f < threshold) return 2                 // warning
    return 3                                    // critical
  }
  return sources.reduce((worst, s) =>
    level(s) > level(worst) ? s : worst,
    sources[0],
  )
}

function formatRelative(iso) {
  if (!iso) return 'Never'
  const then = new Date(iso).getTime()
  const diff = (Date.now() - then) / 1000
  if (diff < 60) return `${Math.floor(diff)}s ago`
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`
  if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`
  return `${Math.floor(diff / 86400)}d ago`
}

function onRowClick(_evt, { item, internalItem }) {
  // Toggle expansion on row click (in addition to the chevron).
  const key = item.key
  const idx = expanded.value.indexOf(key)
  if (idx === -1) expanded.value = [...expanded.value, key]
  else expanded.value = expanded.value.filter(k => k !== key)
}

function openAddSource(artist) {
  editingSource.value = null
  editingArtist.value = artist
  showSourceDialog.value = true
}

function openEditSource(source) {
  editingSource.value = source
  editingArtist.value = { id: source.artist_id, name: source.artist_name, slug: source.artist_slug }
  showSourceDialog.value = true
}

async function removeSource(source) {
  await store.remove(source.id, source.artist_id)
  await refresh()
}

async function toggleSourceEnabled({ source, enabled }) {
  await store.update(source.id, { enabled }, source.artist_id)
  await refresh()
}

async function onSourceSaved() {
  showSourceDialog.value = false
  await refresh()
}

function onArtistCreated(artist) {
  showArtistDialog.value = false
  openAddSource(artist)
}

async function onCheck(source) {
  try {
    const body = await store.checkNow(source.id)
    globalThis.window?.__fcToast?.({
      text: `Check enqueued (event #${body.download_event_id})`,
      type: 'success',
    })
  } catch (e) {
    if (e?.body?.download_event_id) {
      globalThis.window?.__fcToast?.({
        text: 'Already running — see Downloads',
        type: 'info',
      })
      router.push({ path: '/downloads', query: { source_id: source.id } })
    } else {
      globalThis.window?.__fcToast?.({
        text: `Check failed: ${e?.detail || e?.message || e}`,
        type: 'error',
      })
    }
  }
}

async function checkAll(group) {
  let ok = 0
  let conflict = 0
  for (const s of group.sources) {
    if (!s.enabled) continue
    try {
      await store.checkNow(s.id)
      ok += 1
    } catch (e) {
      if (e?.body?.download_event_id) conflict += 1
    }
  }
  const parts = []
  if (ok) parts.push(`${ok} queued`)
  if (conflict) parts.push(`${conflict} already running`)
  globalThis.window?.__fcToast?.({
    text: parts.join(', ') || 'Nothing to check (no enabled sources)',
    type: 'info',
  })
}

function anyChecking(sources) {
  return sources.some(s => store.checkingIds.has(s.id))
}
</script>

<style scoped>
.fc-subs__bar {
  display: flex; gap: 0.75rem; align-items: center;
  padding-bottom: 1rem;
}
.fc-subs__loading, .fc-subs__empty {
  display: flex; justify-content: center; padding: 2rem;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-subs__card {
  background: rgb(var(--v-theme-surface));
}
.fc-subs__name {
  font-weight: 600;
}
.fc-subs__when {
  color: rgb(var(--v-theme-on-surface-variant));
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.fc-subs__zero {
  color: rgb(var(--v-theme-on-surface-variant));
  opacity: 0.6;
}
.fc-subs__sources-row td {
  padding: 0 !important;
  background: rgb(var(--v-theme-surface-light));
}
.fc-subs__sources-cell {
  padding-left: 2rem !important;
  border-top: 1px solid rgb(var(--v-theme-on-surface-variant) / 0.15);
}
.fc-subs__sources-table {
  background: transparent !important;
}
.fc-subs__sources-empty {
  color: rgb(var(--v-theme-on-surface-variant));
  text-align: center;
  padding: 1rem;
}
</style>
