import { isLoggingEnabled, getActiveProvider } from './serverConfig.js';
import { version } from '../package.json';
import {
  getOrCreateSession,
  incrementToolCalls,
  incrementErrors,
  incrementRateLimits,
  incrementGitHubCacheRateLimits,
  updateSessionStats,
  type PersistedSession,
} from './shared/index.js';
import type {
  SessionData,
  ToolCallData,
  ErrorData,
  RateLimitData,
} from './types/session.js';
import { isLocalTool } from './tools/toolNames.js';

class SessionManager {
  private session: PersistedSession;
  private readonly logEndpoint = 'https://octocode-mcp-host.onrender.com/log';

  constructor() {
    this.session = getOrCreateSession();
  }

  getSessionId(): string {
    return this.session.sessionId;
  }

  getSession(): PersistedSession {
    return this.session;
  }

  async logInit(): Promise<void> {
    await this.sendLog('init', {});
  }

  async logToolCall(
    toolName: string,
    repos: string[],
    _mainResearchGoal?: string,
    _researchGoal?: string,
    _reasoning?: string
  ): Promise<void> {
    const result = incrementToolCalls(1);
    if (result.session) {
      this.session = result.session;
    }

    const data: ToolCallData = {
      tool_name: toolName,
      repos: !isLocalTool(toolName) ? repos.map(() => '[redacted]') : [],
      provider: !isLocalTool(toolName) ? getActiveProvider() : undefined,
    };
    await this.sendLog('tool_call', data);
  }

  async logError(toolName: string, errorCode: string): Promise<void> {
    const result = incrementErrors(1);
    if (result.session) {
      this.session = result.session;
    }

    await this.sendLog('error', { error: `${toolName}:${errorCode}` });
  }

  async logRateLimit(data: RateLimitData): Promise<void> {
    const result = data.provider
      ? updateSessionStats({
          rateLimits: 1,
          rateLimitsByProvider: {
            [data.provider]: 1,
          },
        } as Parameters<typeof updateSessionStats>[0])
      : incrementRateLimits(1);
    if (result.session) {
      this.session = result.session;
    }

    if (data.provider === 'github') {
      const githubCacheResult = incrementGitHubCacheRateLimits(1);
      if (githubCacheResult.session) {
        this.session = githubCacheResult.session;
      }
    }

    await this.sendLog('rate_limit', data);
  }

  logPackageRegistryFailure(registry: string): void {
    const result = updateSessionStats({
      packageRegistryFailures: {
        [registry]: 1,
      },
    } as Parameters<typeof updateSessionStats>[0]);
    if (result.session) {
      this.session = result.session;
    }
  }

  private async sendLog(
    intent: 'init' | 'tool_call' | 'error' | 'rate_limit',
    data: ToolCallData | ErrorData | RateLimitData | Record<string, never>
  ): Promise<void> {
    if (intent !== 'init' && !isLoggingEnabled()) {
      return;
    }

    try {
      const payload: SessionData = {
        sessionId: this.session.sessionId,
        intent,
        data,
        timestamp: new Date().toISOString(),
        version,
      };

      await fetch(this.logEndpoint, {
        method: 'POST',
        body: JSON.stringify(payload),
        headers: { 'Content-Type': 'application/json' },
        signal: AbortSignal.timeout(5000),
      });
    } catch {
      void 0;
    }
  }
}

let sessionManager: SessionManager | null = null;

export function initializeSession(): SessionManager {
  if (!sessionManager) {
    sessionManager = new SessionManager();
  }
  return sessionManager;
}

export function getSessionManager(): SessionManager | null {
  return sessionManager;
}

export async function logSessionInit(): Promise<void> {
  const session = getSessionManager();
  if (session) {
    await session.logInit();
  }
}

export async function logToolCall(
  toolName: string,
  repos: string[],
  mainResearchGoal?: string,
  researchGoal?: string,
  reasoning?: string
): Promise<void> {
  const session = getSessionManager();
  if (session) {
    await session.logToolCall(
      toolName,
      repos,
      mainResearchGoal,
      researchGoal,
      reasoning
    );
  }
}

export async function logPromptCall(promptName: string): Promise<void> {
  const session = getSessionManager();
  if (session) {
    await session.logToolCall(promptName, [], undefined, undefined, undefined);
  }
}

export async function logSessionError(
  toolName: string,
  errorCode: string
): Promise<void> {
  const session = getSessionManager();
  if (session) {
    await session.logError(toolName, errorCode);
  }
}

export async function logRateLimit(data: RateLimitData): Promise<void> {
  const session = getSessionManager();
  if (session) {
    await session.logRateLimit(data);
  }
}

export function logPackageRegistryFailure(registry: string): void {
  const session = getSessionManager();
  if (session) {
    session.logPackageRegistryFailure(registry);
  }
}

export function resetSessionManager(): void {
  sessionManager = null;
}
