<script lang="ts" setup>
import { z } from 'zod';
import { formatDistanceToNow } from 'date-fns';
import { LockClosedIcon, LockOpenIcon } from '@heroicons/vue/20/solid';

definePageMeta({ layout: 'admin' });

const { data, error: sourcesError } = await useFetch('/api/admin/sources');
if (sourcesError.value) {
  console.error(sourcesError.value);

  if (sourcesError.value.statusCode === 401) {
    await navigateTo('/admin/login');
  } else {
    throw createError({ statusCode: 500, statusMessage: 'Failed to fetch sources' });
  }
}

type Source = NonNullable<typeof data.value>['sources'][number];
// type Overview = NonNullable<typeof data.value>['overview'];

const sources = computed(() => data.value?.sources ?? []);
const overview = computed(() => data.value?.overview);

// const config = useRuntimeConfig();

const sortKey = ref<keyof Source | ''>('');
const sortOrder = ref<'asc' | 'desc'>('asc');
const selectedFrequency = ref<string>('all');
const showPaywallOnly = ref(false);
const showErrorsOnly = ref(false);
const errorThreshold = ref(5);
const staleHours = ref(24);
const enableTimeFilter = ref(false);
const articleCountFilter = ref<'more' | 'less'>('more');
const articleCountThreshold = ref(100);
const enableArticleFilter = ref(false);

const FREQUENCIES = ['Hourly', '4 Hours', '6 Hours', 'Daily'] as const;

const totalArticles = computed(() => sources.value?.reduce((sum, source) => sum + source.totalArticles, 0) ?? 0);
const filteredArticles = computed(() => filteredSources.value.reduce((sum, source) => sum + source.totalArticles, 0));
const stats = computed(() => {
  if (!filteredSources.value.length) return null;

  return {
    avgProcessSuccess: Math.round(
      filteredSources.value.reduce((sum, s) => sum + (s.processSuccessRate ?? 0), 0) / filteredSources.value.length
    ),
    avgErrorRate: Math.round(
      filteredSources.value.reduce((sum, s) => sum + (s.errorRate ?? 0), 0) / filteredSources.value.length
    ),
    avgArticlesPerDay: Math.round(
      filteredSources.value.reduce((sum, s) => sum + (s.avgPerDay || 0), 0) / filteredSources.value.length
    ),
  };
});
const filteredSources = computed(() => {
  if (!sources.value) return [];

  let filtered = sources.value;

  // frequency filter
  if (selectedFrequency.value !== 'all') {
    filtered = filtered.filter(source => source.frequency === selectedFrequency.value);
  }

  // paywall filter
  if (showPaywallOnly.value) {
    filtered = filtered.filter(source => source.paywall);
  }

  // errors filter
  if (showErrorsOnly.value) {
    filtered = filtered.filter(source => (source.errorRate ?? 0) > errorThreshold.value);
  }

  // stale sources filter
  if (enableTimeFilter.value) {
    const cutoffTime = new Date();
    cutoffTime.setHours(cutoffTime.getHours() - staleHours.value);

    filtered = filtered.filter(source => {
      const lastCheck = new Date(source.lastChecked ?? '');
      return lastCheck > cutoffTime;
    });
  }

  // article count filter
  if (enableArticleFilter.value) {
    filtered = filtered.filter(source => {
      if (articleCountFilter.value === 'more') {
        return source.totalArticles > articleCountThreshold.value;
      }
      return source.totalArticles < articleCountThreshold.value;
    });
  }

  return filtered;
});
const sortedSources = computed(() => {
  if (!sortKey.value) return filteredSources.value;

  const key = sortKey.value as keyof Source;

  return [...filteredSources.value].sort((a, b) => {
    if (key === 'lastChecked') {
      const aTime = new Date(a[key] ?? '').getTime();
      const bTime = new Date(b[key] ?? '').getTime();
      return sortOrder.value === 'asc' ? aTime - bTime : bTime - aTime;
    }

    const aVal = a[key];
    const bVal = b[key];
    return sortOrder.value === 'asc' ? Number(aVal) - Number(bVal) : Number(bVal) - Number(aVal);
  });
});

const toggleSort = (key: keyof Source) => {
  if (sortKey.value === key) {
    sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc';
  } else {
    sortKey.value = key;
    sortOrder.value = 'asc';
  }
};
const formatDate = (dateStr: string) => {
  const date = new Date(dateStr);
  const Y = date.getFullYear();
  const M = String(date.getMonth() + 1).padStart(2, '0');
  const D = String(date.getDate()).padStart(2, '0');
  const h = String(date.getHours()).padStart(2, '0');
  const m = String(date.getMinutes()).padStart(2, '0');
  const s = String(date.getSeconds()).padStart(2, '0');
  return `${Y}-${M}-${D} ${h}:${m}:${s}`;
};

const formatTimeAgo = (dateStr: string | null) => {
  if (!dateStr) return 'Never';
  return formatDistanceToNow(new Date(dateStr), { addSuffix: true });
};

async function addSource() {
  const url = prompt('Enter the URL of the source you want to add');
  if (!url) return;

  const urlSchema = z.string().url();
  const result = urlSchema.safeParse(url);
  if (!result.success) {
    alert('Invalid URL');
    return;
  }

  try {
    await $fetch('/api/admin/sources', {
      method: 'POST',
      body: { url },
    });
    alert('Source added successfully');
  } catch (error) {
    console.error(sourcesError, error);
    throw createError({ statusCode: 500, statusMessage: 'Failed to fetch sources' });
  }
}

// Add health status computation
const getSourceHealth = (source: Source) => {
  const isStale = source.lastChecked
    ? new Date().getTime() - new Date(source.lastChecked).getTime() > 24 * 60 * 60 * 1000
    : true;

  if ((source.errorRate ?? 0) > 10 || isStale) return 'red';
  if ((source.errorRate ?? 0) > 0) return 'yellow';
  return 'green';
};

const getHealthColor = (health: string) => {
  switch (health) {
    case 'red':
      return 'bg-red-500';
    case 'yellow':
      return 'bg-yellow-500';
    case 'green':
      return 'bg-green-500';
    default:
      return 'bg-gray-500';
  }
};

const isSourceStale = (lastChecked: string | null | undefined) => {
  if (!lastChecked) return true;
  return new Date().getTime() - new Date(lastChecked).getTime() > 24 * 60 * 60 * 1000;
};
</script>

<template>
  <div>
    <div class="flex justify-between items-center mb-6">
      <h1 class="text-xl font-medium text-gray-900">Source Analytics</h1>

      <!-- button to add a new source -->
      <button class="border px-4 py-2 rounded hover:cursor-pointer hover:bg-gray-100" @click="addSource">
        Add Source
      </button>
    </div>

    <!-- Overview Section -->
    <div v-if="overview" class="grid grid-cols-4 gap-4 mb-6">
      <div class="col-span-4 bg-white p-4 rounded border">
        <h2 class="text-lg font-medium text-gray-900 mb-4">System Overview</h2>
        <div class="grid grid-cols-4 gap-4">
          <!-- Last Activity -->
          <div class="space-y-2">
            <div class="text-xs text-gray-500 uppercase tracking-wide">Last Activity</div>
            <div>
              <div class="text-sm text-gray-600">Source Check: {{ formatTimeAgo(overview.lastSourceCheck) }}</div>
              <div class="text-sm text-gray-600">
                Article Processed: {{ formatTimeAgo(overview.lastArticleProcessed) }}
              </div>
              <div class="text-sm text-gray-600">Article Fetched: {{ formatTimeAgo(overview.lastArticleFetched) }}</div>
            </div>
          </div>

          <!-- Today's Stats -->
          <div class="space-y-2">
            <div class="text-xs text-gray-500 uppercase tracking-wide">Today's Stats</div>
            <div>
              <div class="text-sm text-gray-600">Articles Fetched: {{ overview.articlesFetchedToday }}</div>
              <div class="text-sm text-gray-600">Articles Processed: {{ overview.articlesProcessedToday }}</div>
              <div class="text-sm text-gray-600">Errors: {{ overview.errorsToday }}</div>
            </div>
          </div>

          <!-- Source Health -->
          <div class="space-y-2">
            <div class="text-xs text-gray-500 uppercase tracking-wide">Source Health</div>
            <div>
              <div class="text-sm text-gray-600">Total Sources: {{ overview.totalSourcesCount }}</div>
              <div
                class="text-sm"
                :class="{
                  'text-red-600': overview.staleSourcesCount > 0,
                  'text-gray-600': overview.staleSourcesCount === 0,
                }"
              >
                Stale Sources: {{ overview.staleSourcesCount }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="grid grid-cols-4 gap-4 mb-6">
      <div class="bg-white p-4 rounded border">
        <div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Avg Process Success</div>
        <div class="text-2xl font-medium text-gray-900">{{ stats?.avgProcessSuccess ?? '-' }}%</div>
      </div>
      <div class="bg-white p-4 rounded border">
        <div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Avg Error Rate</div>
        <div
          class="text-2xl font-medium"
          :class="{ 'text-red-600': (stats?.avgErrorRate ?? 0) > 5, 'text-gray-900': (stats?.avgErrorRate ?? 0) <= 5 }"
        >
          {{ stats?.avgErrorRate ?? '-' }}%
        </div>
      </div>
      <div class="bg-white p-4 rounded border">
        <div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Avg Articles/Day</div>
        <div class="text-2xl font-medium text-gray-900">{{ stats?.avgArticlesPerDay ?? '-' }}</div>
      </div>
    </div>

    <div class="bg-white rounded border p-4 mb-4">
      <div class="flex flex-wrap gap-6 items-center text-sm">
        <div class="flex items-center gap-2">
          <label class="text-gray-600">Frequency:</label>
          <select v-model="selectedFrequency" class="border rounded px-2 py-1.5 text-sm bg-white">
            <option value="all">All</option>
            <option v-for="freq in FREQUENCIES" :key="freq" :value="freq">{{ freq }}</option>
          </select>
        </div>

        <div class="flex items-center gap-2">
          <label class="inline-flex items-center gap-2">
            <input v-model="showPaywallOnly" type="checkbox" class="rounded border-gray-300" />
            <span class="text-gray-600">Paywall only</span>
          </label>
        </div>

        <div class="flex items-center gap-2">
          <label class="inline-flex items-center gap-2">
            <input v-model="showErrorsOnly" type="checkbox" class="rounded border-gray-300" />
            <span class="text-gray-600">Error rate above:</span>
          </label>
          <input
            v-model="errorThreshold"
            type="number"
            min="0"
            max="100"
            :disabled="!showErrorsOnly"
            class="border rounded px-2 py-1.5 w-16 text-sm disabled:opacity-50 bg-white"
          />
          <span class="text-gray-600">%</span>
        </div>

        <div class="flex items-center gap-2">
          <label class="inline-flex items-center gap-2">
            <input v-model="enableTimeFilter" type="checkbox" class="rounded border-gray-300" />
            <span class="text-gray-600">Sources checked within:</span>
          </label>
          <input
            v-model="staleHours"
            type="number"
            min="1"
            :disabled="!enableTimeFilter"
            class="border rounded px-2 py-1.5 w-16 text-sm disabled:opacity-50 bg-white"
          />
          <span class="text-gray-600">hours</span>
        </div>

        <div class="flex items-center gap-2">
          <label class="inline-flex items-center gap-2">
            <input v-model="enableArticleFilter" type="checkbox" class="rounded border-gray-300" />
            <span class="text-gray-600">Articles:</span>
          </label>
          <select
            v-model="articleCountFilter"
            :disabled="!enableArticleFilter"
            class="border rounded px-2 py-1.5 text-sm disabled:opacity-50 bg-white"
          >
            <option value="more">More than</option>
            <option value="less">Less than</option>
          </select>
          <input
            v-model="articleCountThreshold"
            type="number"
            min="0"
            :disabled="!enableArticleFilter"
            class="border rounded px-2 py-1.5 w-20 text-sm disabled:opacity-50 bg-white"
          />
        </div>
      </div>
    </div>

    <div class="text-sm text-gray-600 mb-4">
      Showing {{ filteredArticles }} / {{ totalArticles }} articles from {{ filteredSources.length }} /
      {{ sources?.length ?? 0 }} sources
    </div>

    <div class="bg-white text-gray-800 rounded border overflow-hidden">
      <table class="min-w-full divide-y divide-gray-200">
        <thead>
          <tr class="bg-gray-50">
            <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-8" />
            <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source</th>
            <th
              class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
              @click="toggleSort('lastChecked')"
            >
              Last Checked
              <span v-if="sortKey === 'lastChecked'" class="text-gray-400">{{ sortOrder === 'asc' ? '↑' : '↓' }}</span>
            </th>
            <th
              class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
              @click="toggleSort('errorRate')"
            >
              Error Rate
              <span v-if="sortKey === 'errorRate'" class="text-gray-400">{{ sortOrder === 'asc' ? '↑' : '↓' }}</span>
            </th>
            <th
              class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
              @click="toggleSort('processSuccessRate')"
            >
              Success Rate
              <span v-if="sortKey === 'processSuccessRate'" class="text-gray-400">{{
                sortOrder === 'asc' ? '↑' : '↓'
              }}</span>
            </th>
            <th
              class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
              @click="toggleSort('totalArticles')"
            >
              Total Articles
              <span v-if="sortKey === 'totalArticles'" class="text-gray-400">{{
                sortOrder === 'asc' ? '↑' : '↓'
              }}</span>
            </th>
            <th
              class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
              @click="toggleSort('avgPerDay')"
            >
              Avg/Day
              <span v-if="sortKey === 'avgPerDay'" class="text-gray-400">{{ sortOrder === 'asc' ? '↑' : '↓' }}</span>
            </th>

            <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-8">Paywall</th>
            <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
          </tr>
        </thead>
        <tbody class="divide-y divide-gray-200">
          <tr
            v-for="source in sortedSources"
            :key="source.id"
            class="hover:bg-gray-50/50 transition-colors"
            :class="{
              'bg-red-50 dark:bg-red-900/10': getSourceHealth(source) === 'red',
              'bg-yellow-50 dark:bg-yellow-900/10': getSourceHealth(source) === 'yellow',
              'bg-green-50 dark:bg-green-900/10': getSourceHealth(source) === 'green',
            }"
          >
            <td class="px-4 py-2">
              <span class="inline-block w-3 h-3 rounded-full" :class="getHealthColor(getSourceHealth(source))" />
            </td>
            <td class="px-4 py-2">
              <NuxtLink :to="source.url" target="_blank" class="text-gray-500 hover:underline">{{
                source.name
              }}</NuxtLink>
            </td>
            <td
              class="px-4 py-2"
              :class="{
                'text-gray-400': isSourceStale(source.lastChecked),
                'text-red-600': !source.lastChecked,
              }"
            >
              {{ formatDate(source.lastChecked ?? '') }}
            </td>
            <td class="px-4 py-2" :class="{ 'text-red-600': (source.errorRate ?? 0) > 5 }">
              {{ source.errorRate?.toFixed(1) ?? 'N/A' }}%
            </td>
            <td class="px-4 py-2">{{ source.processSuccessRate?.toFixed(1) ?? 'N/A' }}%</td>
            <td class="px-4 py-2">{{ source.totalArticles }}</td>
            <td class="px-4 py-2">{{ source.avgPerDay ? source.avgPerDay.toFixed(1) : 'N/A' }}</td>

            <td class="px-4 py-2">
              <component
                :is="source.paywall ? LockClosedIcon : LockOpenIcon"
                class="w-4 h-4"
                :class="source.paywall ? 'text-amber-600' : 'text-gray-400'"
              />
            </td>
            <td class="px-4 py-2">
              <NuxtLink :to="`/admin/feed/${source.id}`" class="text-blue-600 hover:underline"> View Feed </NuxtLink>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>
