<script setup lang="ts">
import { ref, computed, onMounted, watch } from "vue";
import { useRulebooksStore } from "@/stores/rulebooks";
import { apiGet } from "@/api/client";
import {
  subscribeProject, unsubscribeProject, getProjectApplicableRules,
} from "@/api/rulebooks";
import type { RulebookTopic } from "@/api/rulebooks";

const props = defineProps<{
  rulebookId: number;
  topics: RulebookTopic[];
  selectedTopicId: number | null;
}>();
const emit = defineEmits<{ "select-topic": [id: number] }>();

const store = useRulebooksStore();
const isCreating = ref(false);
const newTitle = ref("");

const currentRulebook = computed(() =>
  store.rulebooks.find((rb) => rb.id === props.rulebookId),
);

interface ProjectLite { id: number; title: string }
const projects = ref<ProjectLite[]>([]);
// Map<project_id, Set<rulebook_id>>
const subscribedRulebookIds = ref<Map<number, Set<number>>>(new Map());

async function loadProjects() {
  const data = await apiGet<{ projects: ProjectLite[] }>("/api/projects");
  projects.value = data.projects;
  for (const p of projects.value) {
    const result = await getProjectApplicableRules(p.id);
    subscribedRulebookIds.value.set(
      p.id,
      new Set(result.subscribed_rulebooks.map((rb) => rb.id)),
    );
  }
}

function isSubscribed(projectId: number): boolean {
  return subscribedRulebookIds.value.get(projectId)?.has(props.rulebookId) ?? false;
}

async function toggleSubscription(projectId: number, checked: boolean) {
  if (checked) {
    await subscribeProject(projectId, props.rulebookId);
    const set = subscribedRulebookIds.value.get(projectId) || new Set<number>();
    set.add(props.rulebookId);
    subscribedRulebookIds.value.set(projectId, set);
  } else {
    await unsubscribeProject(projectId, props.rulebookId);
    subscribedRulebookIds.value.get(projectId)?.delete(props.rulebookId);
  }
  // trigger reactivity on Map mutation
  subscribedRulebookIds.value = new Map(subscribedRulebookIds.value);
}

async function submitNew() {
  const title = newTitle.value.trim();
  if (!title) return;
  const topic = await store.createTopic(props.rulebookId, { title });
  newTitle.value = "";
  isCreating.value = false;
  emit("select-topic", topic.id);
}

onMounted(loadProjects);
watch(() => props.rulebookId, () => {/* re-render of isSubscribed from existing map */});
</script>

<template>
  <section class="pane">
    <header>
      <h2>Topics</h2>
      <label v-if="currentRulebook" class="always-on-toggle" title="When on, rules from this rulebook load at session start regardless of project context">
        <input
          type="checkbox"
          :checked="currentRulebook.always_on"
          @change="store.toggleAlwaysOn(currentRulebook.id)"
        />
        <span>Always on</span>
      </label>
    </header>
    <ul>
      <li
        v-for="t in topics"
        :key="t.id"
        :class="{ active: t.id === selectedTopicId }"
        @click="emit('select-topic', t.id)"
      >
        {{ t.title }}
      </li>
    </ul>
    <div class="new-topic">
      <button v-if="!isCreating" @click="isCreating = true">+ New topic</button>
      <form v-else @submit.prevent="submitNew">
        <input v-model="newTitle" autofocus placeholder="Topic title (e.g. git-workflow)" />
        <div class="form-buttons">
          <button type="submit">Create</button>
          <button type="button" @click="isCreating = false">Cancel</button>
        </div>
      </form>
    </div>
    <div class="subscriptions">
      <h3>Subscribers</h3>
      <ul class="sub-list">
        <li v-for="p in projects" :key="p.id">
          <label>
            <input
              type="checkbox"
              :checked="isSubscribed(p.id)"
              @change="toggleSubscription(p.id, ($event.target as HTMLInputElement).checked)"
            />
            {{ p.title }}
          </label>
        </li>
      </ul>
    </div>
  </section>
</template>

<style src="@/assets/rules-shared.css" />
<style scoped>
header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.always-on-toggle {
  display: flex; align-items: center; gap: 0.4rem;
  font-size: 0.85rem; opacity: 0.85; cursor: pointer;
  user-select: none;
}
.always-on-toggle input { cursor: pointer; }
ul { list-style: none; padding: 0; margin: 1rem 0; }
li { padding: 0.5rem; cursor: pointer; border-radius: 6px; }
li.active { background: var(--fs-accent-soft); }
li:hover { background: var(--fs-surface-hover); }
/* `.new-topic` and `.sub-list` are deliberately bare (#2444). The first wraps a
   button-or-form whose children style themselves; the second is a `<ul>`, and
   the bare `ul` rule above already gives it list-style, padding and margin —
   a base a class-name check cannot see, since it comes from an element
   selector. Both namespace descendant rules and assume nothing about layout. */
.new-topic input {
  width: 100%; margin-bottom: 0.5rem;
  background: var(--fs-surface-page); color: inherit;
  border: 1px solid var(--fs-border-color); border-radius: 6px;
  padding: 0.5rem;
}
.form-buttons { display: flex; gap: 0.5rem; }
.subscriptions {
  margin-top: 2rem;
  border-top: 1px solid var(--fs-border-color);
  padding-top: 1rem;
}
.subscriptions h3 { font-size: 0.9em; opacity: 0.7; text-transform: uppercase; letter-spacing: 0.05em; }
.sub-list li { cursor: default; }
.sub-list label { display: flex; gap: 0.5rem; align-items: center; cursor: pointer; }
button { cursor: pointer; }
</style>
