<template>
  <div>
    <PageHeader :title="t('pages.runs.title')" />

    <VAlert v-if="runsError" type="error" variant="tonal" class="mt-4">
      {{ t(runsError.messageKey) }}
    </VAlert>

    <VRow class="mt-4" density="compact">
      <VCol cols="12" md="4">
        <VCard variant="tonal">
          <VCardText>
            <div class="text-caption text-medium-emphasis">{{ t("pages.runs.title") }}</div>
            <div class="text-h6 font-weight-bold">{{ totalCount }}</div>
          </VCardText>
        </VCard>
      </VCol>
      <VCol cols="12" md="4">
        <VCard variant="tonal">
          <VCardText class="d-flex align-center justify-space-between ga-2 flex-wrap">
            <div>
              <div class="text-caption text-medium-emphasis">{{ t("pages.runs.waitQueue") }}</div>
              <div class="text-h6 font-weight-bold">{{ waitQueueCount }}</div>
            </div>
            <VBtn size="small" variant="text" icon="mdi-open-in-new" :title="t('pages.runs.details')" :to="{ name: 'wait-queue' }" />
          </VCardText>
        </VCard>
      </VCol>
      <VCol cols="12" md="4">
        <VCard variant="tonal">
          <VCardText class="d-flex align-center justify-space-between ga-2 flex-wrap">
            <div>
              <div class="text-caption text-medium-emphasis">{{ t("pages.runs.pendingApprovals") }}</div>
              <div class="text-h6 font-weight-bold">{{ pendingApprovalsCount }}</div>
            </div>
            <VBtn size="small" variant="text" icon="mdi-open-in-new" :title="t('pages.runs.details')" :to="{ name: 'approvals' }" />
          </VCardText>
        </VCard>
      </VCol>
    </VRow>

    <VCard class="mt-4" variant="outlined">
      <VCardText>
        <VDataTableServer
          v-model:page="tablePage"
          v-model:items-per-page="itemsPerPage"
          :headers="headers"
          :items="runItems"
          :items-length="totalCount"
          :loading="loading"
          :items-per-page-options="itemsPerPageOptions"
          hover
        >
          <template #item.status="{ item }">
            <div class="d-flex justify-center">
              <VChip size="small" variant="tonal" class="font-weight-bold" :color="colorForRunStatus(item.status)">
                {{ item.status }}
              </VChip>
            </div>
          </template>

          <template #item.project="{ item }">
            <RouterLink
              v-if="item.project_id"
              class="text-primary font-weight-bold text-decoration-none"
              :to="{ name: 'project-details', params: { projectId: item.project_id } }"
            >
              {{ item.project_name || item.project_slug || item.project_id }}
            </RouterLink>
            <span v-else class="text-medium-emphasis">-</span>
          </template>

          <template #item.issue="{ item }">
            <a
              v-if="item.issue_url && item.issue_number"
              class="text-primary font-weight-bold text-decoration-none mono"
              :href="item.issue_url"
              target="_blank"
              rel="noopener noreferrer"
            >
              #{{ item.issue_number }}
            </a>
            <span v-else class="text-medium-emphasis">-</span>
          </template>

          <template #item.pr="{ item }">
            <a
              v-if="item.pr_url && item.pr_number"
              class="text-primary font-weight-bold text-decoration-none mono"
              :href="item.pr_url"
              target="_blank"
              rel="noopener noreferrer"
            >
              #{{ item.pr_number }}
            </a>
            <span v-else class="text-medium-emphasis">-</span>
          </template>

          <template #item.started_at="{ item }">
            <span class="mono text-medium-emphasis">{{ formatDateTime(item.started_at, locale) }}</span>
          </template>
          <template #item.finished_at="{ item }">
            <span class="mono text-medium-emphasis">{{ formatDateTime(item.finished_at, locale) }}</span>
          </template>

          <template #item.actions="{ item }">
            <VTooltip :text="t('pages.runs.details')">
              <template #activator="{ props: tipProps }">
                <VBtn
                  v-bind="tipProps"
                  size="small"
                  variant="text"
                  icon="mdi-open-in-new"
                  :to="{ name: 'run-details', params: { runId: item.id } }"
                />
              </template>
            </VTooltip>
          </template>

          <template #no-data>
            <div class="py-8 text-medium-emphasis">
              {{ t("states.noRuns") }}
            </div>
          </template>
        </VDataTableServer>
      </VCardText>
    </VCard>
  </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
import { RouterLink } from "vue-router";
import { useI18n } from "vue-i18n";

import PageHeader from "../shared/ui/PageHeader.vue";
import { ApiError } from "../shared/api/errors";
import { formatDateTime } from "../shared/lib/datetime";
import { colorForRunStatus } from "../shared/lib/chips";
import { bindRealtimePageLifecycle } from "../shared/ws/lifecycle";
import { subscribeRunsRealtime } from "../features/runs/list-realtime";
import type { Run, RunsRealtimeMessage } from "../features/runs/types";

const { t, locale } = useI18n({ useScope: "global" });
const loading = ref(true);
const runsError = ref<ApiError | null>(null);
const runItems = ref<Run[]>([]);
const totalCount = ref(0);
const waitQueueCount = ref(0);
const pendingApprovalsCount = ref(0);
const tablePage = ref(1);
const itemsPerPage = ref(20);
const stopRunsRealtimeRef = ref<(() => void) | null>(null);
const stopLifecycleBindingRef = ref<(() => void) | null>(null);
const itemsPerPageOptions = [10, 20, 50, 100];

const headers = [
  { title: t("pages.runs.status"), key: "status", width: 140, align: "center" },
  { title: t("pages.runs.project"), key: "project", sortable: false, width: 220, align: "center" },
  { title: t("pages.runs.issue"), key: "issue", sortable: false, width: 120, align: "center" },
  { title: t("pages.runs.pr"), key: "pr", sortable: false, width: 120, align: "center" },
  { title: t("pages.runs.triggerLabel"), key: "trigger_label", width: 200, align: "center" },
  { title: t("pages.runs.started"), key: "started_at", width: 180, align: "center" },
  { title: t("pages.runs.finished"), key: "finished_at", width: 180, align: "center" },
  { title: "", key: "actions", sortable: false, width: 72, align: "end" },
] as const;

function applyRunsRealtimeMessage(message: RunsRealtimeMessage): void {
  if (message.type === "error") {
    runsError.value = new ApiError({ kind: "unknown", messageKey: "errors.unknown" });
    loading.value = false;
    return;
  }
  if (!message.pagination) {
    return;
  }
  if (typeof message.wait_queue_count === "number") {
    waitQueueCount.value = message.wait_queue_count;
  }
  if (typeof message.pending_approvals_count === "number") {
    pendingApprovalsCount.value = message.pending_approvals_count;
  }
  const maxPage = Math.max(1, Math.ceil(message.pagination.total_count / message.pagination.page_size));
  if (tablePage.value > maxPage) {
    tablePage.value = maxPage;
    return;
  }
  runItems.value = message.items ?? [];
  totalCount.value = message.pagination.total_count;
  runsError.value = null;
  loading.value = false;
}

function handleInitialRunsRealtimeTimeout(): void {
  runsError.value = new ApiError({ kind: "network", messageKey: "errors.realtimeUnavailable" });
  loading.value = false;
}

function stopRunsRealtime(): void {
  stopRunsRealtimeRef.value?.();
  stopRunsRealtimeRef.value = null;
}

function startRunsRealtime(): void {
  stopRunsRealtime();
  loading.value = true;
  runsError.value = null;
  stopRunsRealtimeRef.value = subscribeRunsRealtime({
    page: tablePage.value,
    pageSize: itemsPerPage.value,
    onMessage: applyRunsRealtimeMessage,
    onInitialMessageTimeout: handleInitialRunsRealtimeTimeout,
  });
}

function stopLifecycleBinding(): void {
  stopLifecycleBindingRef.value?.();
  stopLifecycleBindingRef.value = null;
}

function handlePageSuspend(): void {
  stopRunsRealtime();
}

function handlePageResume(): void {
  startRunsRealtime();
}

onMounted(() => {
  startRunsRealtime();
  stopLifecycleBindingRef.value = bindRealtimePageLifecycle({
    onResume: handlePageResume,
    onSuspend: handlePageSuspend,
  });
});

onBeforeUnmount(() => {
  stopLifecycleBinding();
  stopRunsRealtime();
});

watch(
  itemsPerPage,
  (nextValue, prevValue) => {
    if (nextValue === prevValue) return;
    if (tablePage.value !== 1) {
      tablePage.value = 1;
      return;
    }
    startRunsRealtime();
  },
);

watch(
  tablePage,
  (nextValue, prevValue) => {
    if (nextValue === prevValue) return;
    startRunsRealtime();
  },
);
</script>

<style scoped>
.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
</style>
