<script setup lang="ts">
import { computed, ref, watch, onMounted } from "vue";
import { useRulebooksStore } from "@/stores/rulebooks";
import { useCanonicalSystemsStore } from "@/stores/canonicalSystems";
import type { RuleTier } from "@/api/rulebooks";

const props = defineProps<{ ruleId: number | null; topicId: number | null }>();
const emit = defineEmits<{ close: [] }>();

const store = useRulebooksStore();
const canon = useCanonicalSystemsStore();
const title = ref("");
const statement = ref("");
const whenToApply = ref("");
const tier = ref<RuleTier>("always_on");
const systemIds = ref<number[]>([]);
const why = ref("");
const howToApply = ref("");

const relations = computed(() => store.currentRule?.relations ?? []);

// The label a reader needs to judge an edge, not the stored token.
const RELATION_LABEL: Record<string, { outgoing: string; incoming: string }> = {
  co_surfaces: { outgoing: "arrives with", incoming: "arrives with" },
  overrides: { outgoing: "overrides", incoming: "is overridden by" },
  elaborates: { outgoing: "elaborates", incoming: "is elaborated by" },
};

function relationLabel(kind: string, direction: "outgoing" | "incoming") {
  return RELATION_LABEL[kind]?.[direction] ?? kind;
}

function toggleSystem(id: number) {
  const at = systemIds.value.indexOf(id);
  if (at >= 0) systemIds.value.splice(at, 1);
  else systemIds.value.push(id);
}

const isCreating = ref(props.ruleId === null);

async function load() {
  if (props.ruleId !== null) {
    await store.fetchRule(props.ruleId);
    const r = store.currentRule;
    if (r) {
      title.value = r.title;
      statement.value = r.statement;
      whenToApply.value = r.when_to_apply || "";
      tier.value = r.tier || "always_on";
      systemIds.value = (r.systems ?? []).map((sys) => sys.id);
      why.value = r.why || "";
      howToApply.value = r.how_to_apply || "";
    }
  } else {
    title.value = "";
    statement.value = "";
    whenToApply.value = "";
    tier.value = "always_on";
    systemIds.value = [];
    why.value = "";
    howToApply.value = "";
  }
  await canon.fetchCatalog();
}

async function save() {
  if (!title.value.trim() || !statement.value.trim()) {
    emit("close");
    return;
  }
  const fields = {
    title: title.value,
    statement: statement.value,
    when_to_apply: whenToApply.value,
    tier: tier.value,
    // Always sent, so clearing the last area actually clears it — the server
    // reads a list as "these ARE the areas now".
    system_ids: systemIds.value,
    why: why.value,
    how_to_apply: howToApply.value,
  };
  if (isCreating.value && props.topicId !== null) {
    await store.createRule(props.topicId, fields);
  } else if (props.ruleId !== null) {
    await store.updateRule(props.ruleId, fields);
  }
  emit("close");
}

async function remove() {
  if (props.ruleId === null) return;
  if (!confirm("Delete this rule? This cannot be undone.")) return;
  await store.deleteRule(props.ruleId);
  emit("close");
}

onMounted(load);
watch(() => props.ruleId, load);
</script>

<template>
  <div class="backdrop" @click="save">
    <aside class="slide-over" @click.stop>
      <header>
        <h2>{{ isCreating ? "New rule" : "Edit rule" }}</h2>
        <button v-if="!isCreating" class="trash" @click="remove" aria-label="Delete">🗑</button>
        <button class="close" @click="save" aria-label="Close">×</button>
      </header>
      <label>
        Title
        <input v-model="title" placeholder="e.g. dev is home" />
      </label>
      <label>
        Statement <span class="required">*</span>
        <textarea v-model="statement" rows="3" placeholder="The actionable instruction (1-2 sentences)." />
      </label>
      <label>
        When to apply
        <textarea
          v-model="whenToApply"
          rows="2"
          placeholder="The trigger, not the instruction — “before any git push”, “when a release is being cut”."
        />
      </label>

      <fieldset class="tier">
        <legend>How it reaches a session</legend>
        <label class="tier-opt">
          <input v-model="tier" type="radio" value="always_on" />
          <span>
            <strong>Always on</strong>
            — loaded into every session.
          </span>
        </label>
        <label class="tier-opt">
          <input v-model="tier" type="radio" value="conditional" />
          <span>
            <strong>Conditional</strong>
            — arrives when its trigger fires.
          </span>
        </label>
        <p class="tier-test">
          The test: can you name the trigger <em>without</em> naming a system, an artifact type
          or a moment? If the honest answer is “whenever you are working”, it is always on.
          Conditional costs nothing when it is irrelevant, which is what lets it be as long as
          it needs to be.
        </p>
      </fieldset>

      <fieldset v-if="canon.catalog.length" class="areas">
        <legend>Areas this rule is about</legend>
        <label v-for="entry in canon.catalog" :key="entry.id" class="area-opt">
          <input
            type="checkbox"
            :checked="systemIds.includes(entry.id)"
            @change="toggleSystem(entry.id)"
          />
          <span>{{ entry.name }}</span>
        </label>
        <p class="tier-test">
          What lets this rule reach a project working in that area.
        </p>
      </fieldset>

      <section v-if="relations.length" class="relations">
        <h3>Related rules</h3>
        <ul>
          <li v-for="rel in relations" :key="rel.id" class="relation">
            <span class="relation-kind">{{ relationLabel(rel.kind, rel.direction) }}</span>
            <span class="relation-target">rule #{{ rel.rule_id }}</span>
            <span v-if="rel.note" class="relation-note">{{ rel.note }}</span>
          </li>
        </ul>
        <p class="tier-test">
          Rules that <em>fail together</em> are linked, never merged — a merged rule cannot be
          cited, surfaced or suppressed a clause at a time.
        </p>
      </section>

      <label>
        Why
        <textarea v-model="why" rows="4" placeholder="Rationale — the reason this rule exists." />
      </label>
      <label>
        How to apply
        <textarea v-model="howToApply" rows="4" placeholder="When / where this kicks in." />
      </label>
    </aside>
  </div>
</template>

<style scoped>
.backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 100;
}
.slide-over {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: min(520px, 90vw);
  background: var(--fs-surface-hover);
  border-left: 2px solid var(--fs-accent);
  padding: 1.5rem;
  overflow-y: auto;
  box-shadow: -8px 0 32px rgba(0, 0, 0, 0.3);
}
header { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 1rem; }
header h2 {
  flex: 1; margin: 0;
  font-family: Fraunces, serif; font-style: italic;
}
label { display: block; margin-bottom: 1rem; }
.required { color: var(--fs-accent); }
input, textarea {
  width: 100%; margin-top: 0.25rem;
  background: var(--fs-surface-page); color: inherit;
  border: 1px solid var(--fs-border-color); border-radius: 6px;
  padding: 0.5rem; font: inherit;
  font-family: inherit;
}
fieldset { border: 1px solid var(--fs-border-color); border-radius: var(--fs-radius-md); padding: 0.75rem; margin-bottom: 1rem; }
legend { padding: 0 0.35rem; font-size: 0.8rem; color: var(--fs-text-tertiary); }
.tier-opt, .area-opt { display: flex; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.4rem; font-size: 0.88rem; }
.tier-opt input, .area-opt input { width: auto; margin-top: 0.2rem; accent-color: var(--fs-accent); }
.tier-test { margin: 0.5rem 0 0; font-size: 0.78rem; color: var(--fs-text-tertiary); line-height: 1.45; }

.relations h3 { margin: 0 0 0.5rem; font-size: 0.85rem; color: var(--fs-text-secondary); }
.relations ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.relation { display: flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; font-size: 0.85rem; }
.relation-kind { color: var(--fs-accent); }
.relation-target { color: var(--fs-text-primary); }
.relation-note { width: 100%; font-size: 0.78rem; color: var(--fs-text-tertiary); }

.trash, .close { background: none; border: none; cursor: pointer; opacity: 0.6; font-size: 1.25em; }
.trash:hover, .close:hover { opacity: 1; }
</style>
