import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
import { dirname } from 'node:path';

// Records per-(sub-discussion-channel) state created by the
// `create-sub-discussion` tool and consumed by:
//   1. `before_prompt_build` hook — looks up by (agentId, channelId) to
//      inject the host or guest guide as appendSystemContext.
//   2. `close-sub-discussion` tool — looks up by sub channelId to find
//      the parent channel to post the callback to and to validate that
//      the caller is the original host.
//
// One sub-discussion = one channel. Lifetime: from create-sub-discussion
// return until close-sub-discussion (or gateway-stop / disk corruption).
// We persist to a small JSON file so a gateway restart mid-interview
// doesn't strand both host and guest with no guide.

export type SubDiscussionEntry = {
  subChannelId: string;
  hostAgentId: string;         // the openclaw agentId that called create-sub-discussion
  hostUserId: string;          // the host's Fabric Center userId (session.user.id)
  guestUserIds: string[];      // Fabric Center userIds invited as guests
  hostGuide: string;           // appended to host's session system prompt while in this channel
  guestGuide: string;          // appended to each guest's session system prompt while in this channel
  callbackGuildNodeId: string; // where to post the callback when close is called
  callbackChannelId: string;   // parent channel to post callback to (system msg)
  createdAt: string;           // ISO timestamp
};

type StoreFile = { entries: SubDiscussionEntry[] };

export class SubDiscussionStore {
  private byChannelId = new Map<string, SubDiscussionEntry>();

  constructor(private readonly filePath: string) {
    this.load();
  }

  private load(): void {
    if (!existsSync(this.filePath)) return;
    try {
      const data = JSON.parse(readFileSync(this.filePath, 'utf8')) as StoreFile;
      for (const e of data.entries ?? []) {
        if (e?.subChannelId) this.byChannelId.set(e.subChannelId, e);
      }
    } catch {
      // Corrupt file → start empty; first mutation rewrites cleanly.
    }
  }

  private persist(): void {
    mkdirSync(dirname(this.filePath), { recursive: true });
    const data: StoreFile = { entries: [...this.byChannelId.values()] };
    writeFileSync(this.filePath, JSON.stringify(data, null, 2));
  }

  list(): SubDiscussionEntry[] {
    return [...this.byChannelId.values()];
  }

  find(subChannelId: string): SubDiscussionEntry | undefined {
    return this.byChannelId.get(subChannelId);
  }

  add(entry: SubDiscussionEntry): void {
    this.byChannelId.set(entry.subChannelId, entry);
    this.persist();
  }

  remove(subChannelId: string): SubDiscussionEntry | undefined {
    const e = this.byChannelId.get(subChannelId);
    if (!e) return undefined;
    this.byChannelId.delete(subChannelId);
    this.persist();
    return e;
  }
}
