<script setup lang="ts">
import { onMounted, computed, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useTasksStore } from "@/stores/tasks";
import { useNotesStore } from "@/stores/notes";
import { renderMarkdown } from "@/utils/markdown";
import { relativeTime } from "@/composables/useRelativeTime";
import { apiPost, apiGet } from "@/api/client";
import type { Note } from "@/types/note";
import type { TaskStatus } from "@/types/task";
import StatusBadge from "@/components/StatusBadge.vue";
import PriorityBadge from "@/components/PriorityBadge.vue";
import TagPill from "@/components/TagPill.vue";
import TableOfContents from "@/components/TableOfContents.vue";

const route = useRoute();
const router = useRouter();
const store = useTasksStore();
const notesStore = useNotesStore();
const backlinks = ref<{ type: string; id: number; title: string }[]>([]);
const converting = ref(false);

// Context enrichment
const projectTitle = ref<string | null>(null);
const milestoneName = ref<string | null>(null);
const subTasks = ref<Note[]>([]);

const taskId = computed(() => Number(route.params.id));

const statusCycle: Record<TaskStatus, TaskStatus> = {
  todo: "in_progress",
  in_progress: "done",
  done: "todo",
};

const statusDotClass: Record<TaskStatus, string> = {
  todo: "dot-todo",
  in_progress: "dot-in-progress",
  done: "dot-done",
};

function cycleSubTaskStatus(subTask: Note) {
  if (!subTask.status) return;
  const next = statusCycle[subTask.status as TaskStatus];
  store.patchStatus(subTask.id, next).then(() => {
    const idx = subTasks.value.findIndex((t) => t.id === subTask.id);
    if (idx !== -1) subTasks.value[idx] = { ...subTasks.value[idx], status: next };
  });
}

async function loadContext(task: Note) {
  projectTitle.value = null;
  milestoneName.value = null;
  subTasks.value = [];

  const promises: Promise<void>[] = [];

  if (task.project_id) {
    promises.push(
      apiGet<any>(`/api/projects/${task.project_id}`).then((data) => {
        projectTitle.value = data.title ?? null;
        if (task.milestone_id && data.summary?.milestone_summary) {
          const ms = (data.summary.milestone_summary as Array<{ id: number; title: string }>)
            .find((m) => m.id === task.milestone_id);
          if (ms) milestoneName.value = ms.title;
        }
      }).catch(() => {})
    );
  }

  // Load sub-tasks via the notes endpoint with parent_id filter
  promises.push(
    apiGet<{ notes: Note[]; total: number }>(
      `/api/notes?parent_id=${task.id}&type=task&sort=created_at&order=asc&limit=50`
    ).then((data) => {
      subTasks.value = data.notes;
    }).catch(() => {})
  );

  await Promise.all(promises);
}

async function loadTask(id: number) {
  backlinks.value = [];
  await store.fetchTask(id);
  if (!store.currentTask) return;

  const [bl] = await Promise.allSettled([
    notesStore.fetchBacklinks(id),
    loadContext(store.currentTask),
  ]);
  if (bl.status === "fulfilled") backlinks.value = bl.value;
}

onMounted(() => loadTask(taskId.value));

watch(() => route.params.id, (newId) => {
  if (newId) loadTask(Number(newId));
});

const renderedBody = computed(() => {
  if (!store.currentTask) return "";
  return renderMarkdown(store.currentTask.body);
});

function cycleStatus() {
  if (!store.currentTask) return;
  store.patchStatus(
    store.currentTask.id,
    statusCycle[store.currentTask.status as TaskStatus]
  );
}

const forwardStatus: Record<TaskStatus, TaskStatus | null> = {
  todo: "in_progress",
  in_progress: "done",
  done: null,
};

const advanceLabel = computed(() => {
  const s = store.currentTask?.status as TaskStatus | undefined;
  if (!s) return null;
  const next = forwardStatus[s];
  if (!next) return null;
  return next === "in_progress" ? "→ In Progress" : "→ Done";
});

function advanceStatus() {
  if (!store.currentTask) return;
  const next = forwardStatus[store.currentTask.status as TaskStatus];
  if (next) store.patchStatus(store.currentTask.id, next);
}

function isOverdue(): boolean {
  if (!store.currentTask?.due_date || store.currentTask.status === "done")
    return false;
  const today = new Date().toISOString().slice(0, 10);
  return store.currentTask.due_date < today;
}

async function convertToNote() {
  if (converting.value) return;
  converting.value = true;
  try {
    await notesStore.convertToNote(taskId.value);
    const { useToastStore } = await import("@/stores/toast");
    useToastStore().show("Converted to note");
    router.push(`/notes/${taskId.value}`);
  } catch {
    const { useToastStore } = await import("@/stores/toast");
    useToastStore().show("Failed to convert task", "error");
  } finally {
    converting.value = false;
  }
}

async function onBodyClick(e: MouseEvent) {
  const target = e.target as HTMLElement;

  const tagLink = target.closest(".inline-tag") as HTMLAnchorElement | null;
  if (tagLink) {
    e.preventDefault();
    const tag = tagLink.dataset.tag;
    if (tag) {
      router.push({ path: "/notes", query: { tag } });
    }
    return;
  }

  const wikilink = target.closest(".wikilink") as HTMLAnchorElement | null;
  if (wikilink) {
    e.preventDefault();
    const title = wikilink.dataset.title;
    if (title) {
      try {
        const note = await apiPost<Note>(
          "/api/notes/resolve-title",
          { title }
        );
        router.push(`/notes/${note.id}`);
      } catch {
        const { useToastStore } = await import("@/stores/toast");
        useToastStore().show(`Failed to resolve note "${title}"`, "error");
      }
    }
  }
}

function onTagClick(tag: string) {
  router.push({ path: "/tasks", query: { tag } });
}

// Sub-task progress
const subTaskProgress = computed(() => {
  if (!subTasks.value.length) return null;
  const done = subTasks.value.filter((t) => t.status === "done").length;
  const total = subTasks.value.length;
  return { done, total, pct: Math.round((done / total) * 100) };
});
</script>

<template>
  <div class="viewer-layout">
    <main class="viewer">
      <p v-if="store.loading">Loading...</p>
      <template v-else-if="store.currentTask">
        <div class="toolbar">
          <router-link to="/tasks" class="btn-back">← Tasks</router-link>
          <router-link
            :to="`/tasks/${store.currentTask.id}/edit`"
            class="btn-edit"
          >
            Edit
          </router-link>
          <button
            v-if="advanceLabel"
            class="btn-advance"
            @click="advanceStatus"
          >
            {{ advanceLabel }}
          </button>
          <button
            class="btn-convert"
            @click="convertToNote"
            :disabled="converting"
          >
            {{ converting ? "Converting..." : "Convert to Note" }}
          </button>
        </div>

        <!-- Breadcrumb: parent task → project → milestone -->
        <div
          v-if="store.currentTask.parent_id || store.currentTask.project_id"
          class="context-bar"
        >
          <router-link
            v-if="store.currentTask.parent_id"
            :to="`/tasks/${store.currentTask.parent_id}`"
            class="ctx-crumb ctx-crumb-parent"
          >
            ↑ {{ store.currentTask.parent_title || "Parent task" }}
          </router-link>
          <router-link
            v-if="store.currentTask.project_id && projectTitle"
            :to="`/projects/${store.currentTask.project_id}`"
            class="ctx-crumb ctx-crumb-project"
          >
            {{ projectTitle }}
          </router-link>
          <span v-if="milestoneName" class="ctx-crumb ctx-crumb-milestone">
            {{ milestoneName }}
          </span>
        </div>

        <h1>{{ store.currentTask.title || "Untitled" }}</h1>
        <p class="meta">
          Updated {{ relativeTime(store.currentTask.updated_at) }}
          &middot;
          Created {{ relativeTime(store.currentTask.created_at) }}
        </p>
        <div class="badges">
          <StatusBadge
            :status="store.currentTask.status!"
            clickable
            @click="cycleStatus"
          />
          <PriorityBadge :priority="store.currentTask.priority!" />
          <span
            v-if="store.currentTask.due_date"
            :class="['due-date', { overdue: isOverdue() }]"
          >
            Due: {{ store.currentTask.due_date }}
          </span>
        </div>
        <div class="tags" v-if="store.currentTask.tags.length">
          <TagPill
            v-for="tag in store.currentTask.tags"
            :key="tag"
            :tag="tag"
            @click="onTagClick"
          />
        </div>
        <div
          class="body prose"
          v-html="renderedBody"
          @click="onBodyClick"
        ></div>

        <!-- Sub-tasks -->
        <div v-if="subTasks.length" class="subtasks">
          <div class="subtasks-header">
            <h2 class="subtasks-title">Sub-tasks</h2>
            <span v-if="subTaskProgress" class="subtasks-progress">
              {{ subTaskProgress.done }}/{{ subTaskProgress.total }}
              <span class="subtasks-pct">({{ subTaskProgress.pct }}%)</span>
            </span>
          </div>
          <div v-if="subTaskProgress" class="subtasks-track">
            <div class="subtasks-fill" :style="{ width: subTaskProgress.pct + '%' }"></div>
          </div>
          <ul class="subtasks-list">
            <li
              v-for="sub in subTasks"
              :key="sub.id"
              class="subtask-row"
            >
              <button
                :class="['sub-dot', statusDotClass[sub.status as TaskStatus] ?? 'dot-todo']"
                :title="`${sub.status} — click to advance`"
                @click="cycleSubTaskStatus(sub)"
              ></button>
              <router-link :to="`/tasks/${sub.id}/edit`" class="sub-title" :class="{ 'sub-done': sub.status === 'done' }">
                {{ sub.title || "Untitled" }}
              </router-link>
              <span v-if="sub.due_date" class="sub-due">{{ sub.due_date }}</span>
            </li>
          </ul>
        </div>

        <div v-if="backlinks.length" class="backlinks">
          <h2>Backlinks</h2>
          <ul class="backlinks-list">
            <li v-for="link in backlinks" :key="`${link.type}-${link.id}`" class="backlink-item">
              <span class="backlink-type">{{ link.type }}</span>
              <router-link
                :to="`/${link.type === 'note' ? 'notes' : 'tasks'}/${link.id}`"
                class="backlink-link"
              >
                {{ link.title || "Untitled" }}
              </router-link>
            </li>
          </ul>
        </div>
      </template>
      <p v-else>Task not found.</p>
    </main>
    <TableOfContents
      v-if="store.currentTask?.body"
      :body="store.currentTask.body"
      class="toc-sidebar"
    />
  </div>
</template>

<style src="@/assets/viewer-shared.css" />
<style scoped>
.viewer-layout {
  display: flex;
  max-width: 1400px;
  margin: 0 auto;
  gap: 2rem;
}
.viewer {
  flex: 1;
  min-width: 0;
  max-width: 1100px;
  margin: 2rem 0;
  padding: 0 1rem;
}
.toc-sidebar {
  margin-top: 2rem;
}
@media (max-width: 1200px) {
  .toc-sidebar {
    display: none;
  }
}
.toolbar {
  display: flex;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.btn-back,
.btn-edit {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text-secondary);
  text-decoration: none;
  cursor: pointer;
  font-size: 0.9rem;
}
.btn-back:hover,
.btn-edit:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.btn-advance {
  padding: 0.45rem 1rem;
  background: linear-gradient(135deg, #6366f1, #4f46e5);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
  transition: opacity 0.15s;
}
.btn-advance:hover {
  opacity: 0.88;
}
.btn-convert {
  margin-left: auto;
  padding: 0.3rem 0.75rem;
  background: var(--color-bg-secondary);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.85rem;
}
.btn-convert:hover {
  background: var(--color-primary);
  color: #fff;
  border-color: var(--color-primary);
}
.btn-convert:disabled {
  opacity: 0.6;
  cursor: default;
}

.meta {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin: 0 0 0.75rem;
}
.badges {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.due-date {
  font-size: 0.85rem;
  color: var(--color-text-secondary);
}
.due-date.overdue {
  color: var(--color-overdue);
  font-weight: 600;
}
.tags {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

/* Sub-tasks */
.subtasks {
  margin-top: 2rem;
  border-top: 1px solid var(--color-border);
  padding-top: 1rem;
}
.subtasks-header {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-bottom: 0.4rem;
}
.subtasks-title {
  font-size: 1rem;
  margin: 0;
  font-weight: 600;
}
.subtasks-progress {
  font-size: 0.8rem;
  color: var(--color-text-muted);
}
.subtasks-pct {
  color: var(--color-text-muted);
}
.subtasks-track {
  height: 4px;
  background: var(--color-bg-secondary);
  border-radius: 2px;
  margin-bottom: 0.75rem;
  overflow: hidden;
}
.subtasks-fill {
  height: 100%;
  background: var(--color-status-done, #22c55e);
  border-radius: 2px;
  transition: width 0.3s ease;
}
.subtasks-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.subtask-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius-sm);
}
.subtask-row:hover {
  background: var(--color-bg-secondary);
}
.sub-dot {
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: transform 0.1s, opacity 0.1s;
}
.sub-dot:hover {
  transform: scale(1.25);
  opacity: 0.8;
}
.dot-todo {
  background: transparent;
  border: 2px solid var(--color-text-muted);
}
.dot-in-progress {
  background: var(--color-status-in-progress, #3b82f6);
}
.dot-done {
  background: var(--color-status-done, #22c55e);
}
.sub-title {
  flex: 1;
  font-size: 0.9rem;
  color: var(--color-text);
  text-decoration: none;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sub-title:hover {
  color: var(--color-primary);
}
.sub-title.sub-done {
  color: var(--color-text-muted);
  text-decoration: line-through;
}
.sub-due {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.backlinks {
  margin-top: 2rem;
  border-top: 1px solid var(--color-border);
  padding-top: 1rem;
}
.backlinks h2 {
  font-size: 1.1rem;
  margin: 0 0 0.75rem;
}
.backlinks-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.backlink-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.backlink-link {
  color: var(--color-text);
  text-decoration: none;
  font-size: 0.95rem;
}
.backlink-link:hover {
  color: var(--color-primary);
}
.backlink-type {
  font-size: 0.75rem;
  text-transform: uppercase;
  color: var(--color-text-muted);
  background: var(--color-bg-secondary);
  padding: 0.1rem 0.4rem;
  border-radius: var(--radius-sm);
}
</style>
