import fs from 'fs';
import path from 'path';

export interface VisitorSettings {
  is_enabled: boolean;
  show_active_visitors: boolean;
  show_total_visitors: boolean;
  baseline_active: number;
  baseline_total: number;
}

export interface VisitorStatsResponse {
  activeVisitors: number;
  totalVisitors: number;
  settings: VisitorSettings;
}

const DEFAULT_SETTINGS: VisitorSettings = {
  is_enabled: true,
  show_active_visitors: true,
  show_total_visitors: true,
  baseline_active: 0,
  baseline_total: 1317970,
};

class VisitorStore {
  private activeSessions: Map<string, { lastPing: number; isCountedInTotal: boolean }> = new Map();
  private totalVisitors: number = 280;
  private settings: VisitorSettings = { ...DEFAULT_SETTINGS };
  private filePath: string = path.join(process.cwd(), 'data', 'visitor_stats.json');

  constructor() {
    this.loadFromDisk();
  }

  private loadFromDisk(): void {
    try {
      if (fs.existsSync(this.filePath)) {
        const raw = fs.readFileSync(this.filePath, 'utf-8');
        const data = JSON.parse(raw);
        if (typeof data.totalVisitors === 'number') {
          this.totalVisitors = data.totalVisitors;
        }
        if (data.settings && typeof data.settings === 'object') {
          this.settings = { ...DEFAULT_SETTINGS, ...data.settings };
        }
      } else {
        this.saveToDisk();
      }
    } catch (e) {
      console.warn('[VisitorStore] Failed to load visitor stats from disk, using defaults:', e);
    }
  }

  private saveToDisk(): void {
    try {
      const dir = path.dirname(this.filePath);
      if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
      }
      const data = {
        updatedAt: new Date().toISOString(),
        totalVisitors: this.totalVisitors,
        settings: this.settings,
      };
      fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
    } catch (e) {
      console.error('[VisitorStore] Failed to save visitor stats to disk:', e);
    }
  }

  /**
   * Remove inactive sessions older than 30 seconds
   */
  private pruneSessions(): void {
    const now = Date.now();
    const expiryWindow = 30000; // 30 seconds
    for (const [clientId, session] of this.activeSessions.entries()) {
      if (now - session.lastPing > expiryWindow) {
        this.activeSessions.delete(clientId);
      }
    }
  }

  /**
   * Handle client heartbeat ping.
   * Increments total count for new client sessions, updates last active timestamp, and returns real stats.
   */
  public ping(clientId: string): VisitorStatsResponse {
    this.pruneSessions();
    const now = Date.now();

    const existing = this.activeSessions.get(clientId);
    if (!existing) {
      // Brand new session detected
      this.activeSessions.set(clientId, { lastPing: now, isCountedInTotal: true });
      this.totalVisitors += 1;
      this.saveToDisk();
    } else {
      // Existing session ping update
      existing.lastPing = now;
    }

    return this.getStats();
  }

  /**
   * Get current real-time stats
   */
  public getStats(): VisitorStatsResponse {
    this.pruneSessions();

    const realActiveCount = this.activeSessions.size;
    const computedActive = Math.max(1, realActiveCount + (this.settings.baseline_active || 0));
    const computedTotal = Math.max(0, this.totalVisitors + (this.settings.baseline_total || 0));

    return {
      activeVisitors: computedActive,
      totalVisitors: computedTotal,
      settings: { ...this.settings },
    };
  }

  /**
   * Update admin settings for counters
   */
  public updateSettings(newSettings: Partial<VisitorSettings>): VisitorStatsResponse {
    this.settings = {
      ...this.settings,
      ...newSettings,
    };
    this.saveToDisk();
    return this.getStats();
  }

  /**
   * Reset stats (active sessions, total visitors, or both)
   */
  public resetStats(type: 'active' | 'total' | 'all', customActive?: number, customTotal?: number): VisitorStatsResponse {
    if (type === 'active' || type === 'all') {
      this.activeSessions.clear();
      if (typeof customActive === 'number') {
        this.settings.baseline_active = customActive;
      }
    }

    if (type === 'total' || type === 'all') {
      this.totalVisitors = 0;
      if (typeof customTotal === 'number') {
        this.settings.baseline_total = customTotal;
      }
    }

    this.saveToDisk();
    return this.getStats();
  }

  /**
   * Directly set baseline counts
   */
  public setCustomCounts(baselineActive?: number, baselineTotal?: number): VisitorStatsResponse {
    if (typeof baselineActive === 'number') {
      this.settings.baseline_active = baselineActive;
    }
    if (typeof baselineTotal === 'number') {
      this.settings.baseline_total = baselineTotal;
    }
    this.saveToDisk();
    return this.getStats();
  }
}

export const visitorStore = new VisitorStore();
