import { prisma } from './database';
import { readFile } from 'fs/promises';
import { join } from 'path';
import { getToday, parseDate } from '@/lib/date-utils';

export interface SystemInfo {
  version: string;
  environment: string;
  database: {
    totalTasks: number;
    totalUsers: number;
    totalBackups: number;
    databaseSize: string;
    totalTags: number; // Ajout pour compatibilité
    totalDailies: number; // Ajout pour compatibilité
    size: string; // Alias pour databaseSize
  };
  backups: {
    totalBackups: number;
    lastBackup?: string;
  };
  app: {
    version: string;
    environment: string;
  };
  uptime: string;
  lastUpdate: string;
}

export class SystemInfoService {
  /**
   * Récupère les informations système complètes
   */
  static async getSystemInfo(): Promise<SystemInfo> {
    try {
      const [packageInfo, dbStats] = await Promise.all([
        this.getPackageInfo(),
        this.getDatabaseStats(),
      ]);

      return {
        version: packageInfo.version,
        environment: process.env.NODE_ENV || 'development',
        database: {
          ...dbStats,
          totalTags: dbStats.totalTags || 0,
          totalDailies: dbStats.totalDailies || 0,
          size: dbStats.databaseSize,
        },
        backups: {
          totalBackups: dbStats.totalBackups,
          lastBackup: undefined, // TODO: Implement backup tracking
        },
        app: {
          version: packageInfo.version,
          environment: process.env.NODE_ENV || 'development',
        },
        uptime: this.getUptime(),
        lastUpdate: this.getLastUpdate(),
      };
    } catch (error) {
      console.error('Error getting system info:', error);
      throw new Error('Failed to get system information');
    }
  }

  /**
   * Lit les informations du package.json
   */
  private static async getPackageInfo(): Promise<{
    version: string;
    name: string;
  }> {
    try {
      const packagePath = join(process.cwd(), 'package.json');
      const packageContent = await readFile(packagePath, 'utf-8');
      const packageJson = JSON.parse(packageContent);

      return {
        name: packageJson.name || 'TowerControl',
        version: packageJson.version || '1.0.0',
      };
    } catch (error) {
      console.error('Error reading package.json:', error);
      return {
        name: 'TowerControl',
        version: '1.0.0',
      };
    }
  }

  /**
   * Récupère les statistiques de la base de données
   */
  private static async getDatabaseStats() {
    try {
      const [totalTasks, totalUsers, totalBackups, totalTags, totalDailies] =
        await Promise.all([
          prisma.task.count(),
          prisma.userPreferences.count(),
          // Pour les backups, on compte les fichiers via le service backup
          this.getBackupCount(),
          prisma.tag.count(),
          prisma.dailyCheckbox.count(),
        ]);

      return {
        totalTasks,
        totalUsers,
        totalBackups,
        totalTags,
        totalDailies,
        databaseSize: await this.getDatabaseSize(),
      };
    } catch (error) {
      console.error('Error getting database stats:', error);
      return {
        totalTasks: 0,
        totalUsers: 0,
        totalBackups: 0,
        databaseSize: 'N/A',
      };
    }
  }

  /**
   * Compte le nombre de sauvegardes
   */
  private static async getBackupCount(): Promise<number> {
    try {
      // Import dynamique pour éviter les dépendances circulaires
      const { backupService } = await import(
        '@/services/data-management/backup'
      );
      const backups = await backupService.listBackups();
      return backups.length;
    } catch (error) {
      console.error('Error counting backups:', error);
      return 0;
    }
  }

  /**
   * Estime la taille de la base de données
   */
  private static async getDatabaseSize(): Promise<string> {
    try {
      const { stat } = await import('fs/promises');
      const { resolve } = await import('path');

      // Utiliser la même logique que le service de backup pour trouver la DB
      let dbPath: string;
      if (process.env.BACKUP_DATABASE_PATH) {
        dbPath = resolve(process.cwd(), process.env.BACKUP_DATABASE_PATH);
      } else if (process.env.DATABASE_URL) {
        dbPath = resolve(process.env.DATABASE_URL.replace('file:', ''));
      } else {
        dbPath = resolve(process.cwd(), 'prisma', 'dev.db');
      }

      const stats = await stat(dbPath);

      // Convertir en format lisible
      const bytes = stats.size;
      if (bytes === 0) return '0 B';

      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));

      return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
    } catch (error) {
      console.error('Error getting database size:', error);
      return 'N/A';
    }
  }

  /**
   * Calcule l'uptime du processus
   */
  private static getUptime(): string {
    const uptime = process.uptime();
    const hours = Math.floor(uptime / 3600);
    const minutes = Math.floor((uptime % 3600) / 60);
    const seconds = Math.floor(uptime % 60);

    if (hours > 0) {
      return `${hours}h ${minutes}m`;
    } else if (minutes > 0) {
      return `${minutes}m ${seconds}s`;
    } else {
      return `${seconds}s`;
    }
  }

  /**
   * Retourne une date de dernière mise à jour fictive
   * (dans un vrai projet, cela viendrait d'un système de déploiement)
   */
  private static getLastUpdate(): string {
    // Pour l'instant, on utilise la date de modification du package.json
    try {
      const fs = require('fs'); // eslint-disable-line @typescript-eslint/no-require-imports
      const packagePath = join(process.cwd(), 'package.json');
      const stats = fs.statSync(packagePath);
      const now = getToday();
      const lastModified = parseDate(stats.mtime.toISOString());
      const diffTime = Math.abs(now.getTime() - lastModified.getTime());
      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

      if (diffDays === 1) {
        return 'Il y a 1 jour';
      } else if (diffDays < 7) {
        return `Il y a ${diffDays} jours`;
      } else if (diffDays < 30) {
        const weeks = Math.floor(diffDays / 7);
        return `Il y a ${weeks} semaine${weeks > 1 ? 's' : ''}`;
      } else {
        const months = Math.floor(diffDays / 30);
        return `Il y a ${months} mois`;
      }
    } catch {
      return 'Il y a 2 jours';
    }
  }
}
