import type { UserSession } from "./types";
import { logger } from "./logger";

class SessionManager {
  private sessions = new Map<string, UserSession>();
  private userSessions = new Map<string, string[]>();

  getOrCreate(
    sessionId: string,
    email: string,
    cwd: string,
    model: string,
    groupSlug?: string | null,
    context?: string,
    contextId?: string,
  ): UserSession {
    let session = this.sessions.get(sessionId);

    if (!session) {
      session = {
        sessionId,
        email,
        cwd,
        model,
        piProcess: null,
        ws: null,
        lastActivity: Date.now(),
        idleTimer: null,
        streamBuffer: "",
        isGenerating: false,
        systemContextSent: false,
        messages: [],
        meta: {
          id: sessionId,
          title: "",
          model,
          cwd,
          groupSlug: groupSlug || null,
          context,
          contextId,
          createdAt: Date.now(),
          updatedAt: Date.now(),
          messageCount: 0,
          cost: {
            inputTokens: 0,
            outputTokens: 0,
            totalUSD: 0,
          },
        },
      };

      this.sessions.set(sessionId, session);

      const userSessionIds = this.userSessions.get(email) || [];
      userSessionIds.push(sessionId);
      this.userSessions.set(email, userSessionIds);
    }

    session.lastActivity = Date.now();
    return session;
  }

  getSession(sessionId: string): UserSession | null {
    return this.sessions.get(sessionId) || null;
  }

  getUserSessions(email: string): UserSession[] {
    const sessionIds = this.userSessions.get(email) || [];
    return sessionIds
      .map((id) => this.sessions.get(id))
      .filter((s): s is UserSession => s !== undefined);
  }

  deleteSession(sessionId: string): void {
    const session = this.sessions.get(sessionId);
    if (!session) return;

    if (session.idleTimer) {
      clearTimeout(session.idleTimer);
    }

    // Clean up sidecar subscriptions
    if (session._sidecarUnsub) {
      session._sidecarUnsub();
    }
    if (session._claudeKill) {
      session._claudeKill();
    }

    this.sessions.delete(sessionId);

    const userSessionIds = this.userSessions.get(session.email);
    if (userSessionIds) {
      const filtered = userSessionIds.filter(
        (id) => id !== sessionId
      );
      if (filtered.length > 0) {
        this.userSessions.set(session.email, filtered);
      } else {
        this.userSessions.delete(session.email);
      }
    }
  }

  attachWs(sessionId: string, ws: any): void {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.ws = ws;
      session.lastActivity = Date.now();

      if (session.idleTimer) {
        clearTimeout(session.idleTimer);
        session.idleTimer = null;
      }
    }
  }

  detachWs(sessionId: string): void {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.ws = null;
      session.lastActivity = Date.now();
    }
  }

  setIdleTimeout(sessionId: string, timeoutMs: number): void {
    const session = this.sessions.get(sessionId);
    if (!session) return;

    if (session.idleTimer) {
      clearTimeout(session.idleTimer);
    }

    session.idleTimer = setTimeout(() => {
      logger.info('Session idle timeout reached, cleaning up', { sessionId, timeoutMs });
      this.deleteSession(sessionId);
    }, timeoutMs);
  }

  updateActivity(sessionId: string): void {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.lastActivity = Date.now();
    }
  }

  getAllSessions(): UserSession[] {
    return Array.from(this.sessions.values());
  }
}

export const sessionManager = new SessionManager();
