import { defineStore } from "pinia";
import { ref } from "vue";
import { Store as TauriStore } from "@tauri-apps/plugin-store";
import {
  api,
  type IncomingMessage,
  type MessageDestination,
} from "@/lib/api";
import { Events, on } from "@/lib/events";

const STORE_FILE = "outbox.json";
const OUTBOX_KEY = "outbox";
const OUTBOX_CAP = 100;

export interface OutboxEntry {
  id: string;
  destination: MessageDestination;
  topicB64: string;
  payloadB64: string;
  sentAt: number;
  /** "pending" until we resolve message_status, then daemon-reported value. */
  status: string;
}

export const useMessagesStore = defineStore("messages", () => {
  const inbox = ref<IncomingMessage[]>([]);
  const outbox = ref<OutboxEntry[]>([]);
  const loading = ref(false);
  const error = ref<string | null>(null);

  let store: TauriStore | null = null;
  let unlisten: (() => void) | null = null;

  async function ensureStore() {
    if (!store) {
      store = await TauriStore.load(STORE_FILE);
      const saved = (await store.get<OutboxEntry[]>(OUTBOX_KEY)) ?? [];
      outbox.value = saved;
    }
    return store;
  }

  async function persistOutbox() {
    const s = await ensureStore();
    await s.set(OUTBOX_KEY, outbox.value.slice(-OUTBOX_CAP));
    await s.save();
  }

  async function bootstrap() {
    await ensureStore();
    if (!unlisten) {
      unlisten = await on<IncomingMessage>(Events.MessageIncoming, (e) => {
        // Emitted from src-tauri/src/poller.rs every time the daemon
        // long-poll resolves with an inbound message.
        inbox.value = [e.payload, ...inbox.value].slice(0, 200);
      });
    }
  }

  async function refreshInbox() {
    loading.value = true;
    error.value = null;
    try {
      // The poller's ring buffer is the source of truth; the page just
      // catches up after navigation.
      const list = await api.inboxMessages();
      inbox.value = list.slice().reverse(); // newest first
    } catch (e) {
      error.value = String(e);
    } finally {
      loading.value = false;
    }
  }

  async function clearInbox() {
    await api.inboxClear();
    inbox.value = [];
  }

  async function send(
    destination: MessageDestination,
    topicB64: string,
    payloadB64: string,
  ) {
    const receipt = await api.sendMessage(destination, topicB64, payloadB64);
    outbox.value.push({
      id: receipt.id,
      destination,
      topicB64,
      payloadB64,
      sentAt: Date.now(),
      status: "pending",
    });
    if (outbox.value.length > OUTBOX_CAP) {
      outbox.value = outbox.value.slice(-OUTBOX_CAP);
    }
    await persistOutbox();
    return receipt;
  }

  async function refreshOutboxStatus(id: string) {
    try {
      const status = await api.messageStatus(id);
      const entry = outbox.value.find((o) => o.id === id);
      if (entry) {
        const v = (status as { state?: unknown }).state;
        entry.status = typeof v === "string" ? v : JSON.stringify(status);
        await persistOutbox();
      }
    } catch (e) {
      const entry = outbox.value.find((o) => o.id === id);
      if (entry) entry.status = `error: ${String(e)}`;
    }
  }

  async function clearOutbox() {
    outbox.value = [];
    await persistOutbox();
  }

  function dispose() {
    unlisten?.();
    unlisten = null;
  }

  return {
    inbox,
    outbox,
    loading,
    error,
    bootstrap,
    refreshInbox,
    clearInbox,
    send,
    refreshOutboxStatus,
    clearOutbox,
    dispose,
  };
});
