import { Express, Request, Response } from "express";
import { db } from "./db";
import { users, teams, players, coaches } from "@shared/schema";
import { sql } from "drizzle-orm";
import os from "os";
import process from "process";
import { requireAuth } from "./local-auth";

interface SystemHealth {
  database: {
    status: "healthy" | "warning" | "error";
    connectionTime: number;
    activeConnections: number;
    queries: Array<{ query: string; duration: number; status: string }>;
  };
  server: {
    status: "healthy" | "warning" | "error";
    uptime: number;
    memory: { used: number; total: number; percentage: number };
    cpu: { usage: number; cores: number };
    responseTime: number;
  };
  authentication: {
    status: "healthy" | "warning" | "error";
    activeSessions: number;
    failedAttempts: number;
    lastLogin: string;
  };
  api: {
    endpoints: Array<{
      path: string;
      method: string;
      status: "healthy" | "error";
      responseTime: number;
      lastChecked: string;
    }>;
  };
}

interface ErrorLog {
  id: string;
  timestamp: string;
  level: "error" | "warning" | "info";
  message: string;
  stack?: string;
  route?: string;
  userId?: string;
}

// In-memory storage for error logs (in production, use persistent storage)
const errorLogs: ErrorLog[] = [];
const performanceMetrics: any[] = [];

// Middleware to capture errors and performance data
export const debugMiddleware = (req: Request, res: Response, next: any) => {
  const startTime = Date.now();
  
  // Capture response time
  res.on('finish', () => {
    const responseTime = Date.now() - startTime;
    
    // Log slow requests
    if (responseTime > 1000) {
      addErrorLog({
        level: "warning",
        message: `Slow request detected: ${req.method} ${req.path} - ${responseTime}ms`,
        route: req.path,
        userId: (req.user as any)?.id
      });
    }
    
    // Store performance metrics
    performanceMetrics.push({
      timestamp: new Date().toISOString(),
      method: req.method,
      path: req.path,
      responseTime,
      statusCode: res.statusCode,
      userAgent: req.get('User-Agent'),
      ip: req.ip
    });
    
    // Keep only last 1000 metrics
    if (performanceMetrics.length > 1000) {
      performanceMetrics.splice(0, performanceMetrics.length - 1000);
    }
  });
  
  next();
};

// Helper function to add error logs
export const addErrorLog = (log: Omit<ErrorLog, 'id' | 'timestamp'>) => {
  errorLogs.push({
    id: Math.random().toString(36).substr(2, 9),
    timestamp: new Date().toISOString(),
    ...log
  });
  
  // Keep only last 500 logs
  if (errorLogs.length > 500) {
    errorLogs.splice(0, errorLogs.length - 500);
  }
};

// Global error handler
export const errorHandler = (error: any, req: Request, res: Response, next: any) => {
  addErrorLog({
    level: "error",
    message: error.message || "Unknown error occurred",
    stack: error.stack,
    route: req.path,
    userId: (req.user as any)?.id
  });
  
  console.error("Application Error:", error);
  
  if (!res.headersSent) {
    res.status(500).json({
      message: "Internal server error",
      error: process.env.NODE_ENV === 'development' ? error.message : undefined
    });
  }
};

async function checkDatabaseHealth(): Promise<SystemHealth['database']> {
  const startTime = Date.now();
  
  try {
    // Test database connection with a simple query
    await db.select().from(users).limit(1);
    const connectionTime = Date.now() - startTime;
    
    // Get active connections (simplified for compatibility)
    let activeConnections = 1; // Default to 1 active connection
    try {
      // Simple connection test instead of pg_stat_activity query
      await db.select().from(users).limit(1);
      activeConnections = 1;
    } catch (error) {
      console.warn("Could not verify database connection:", error);
      activeConnections = 0;
    }
    
    // Get recent query performance
    const recentQueries = performanceMetrics
      .filter(m => m.path.startsWith('/api/') && Date.now() - new Date(m.timestamp).getTime() < 300000) // Last 5 minutes
      .slice(-10)
      .map(m => ({
        query: `${m.method} ${m.path}`,
        duration: m.responseTime,
        status: m.statusCode < 400 ? 'success' : 'error'
      }));
    
    return {
      status: connectionTime < 100 ? "healthy" : connectionTime < 500 ? "warning" : "error",
      connectionTime,
      activeConnections,
      queries: recentQueries
    };
  } catch (error) {
    return {
      status: "error",
      connectionTime: Date.now() - startTime,
      activeConnections: 0,
      queries: []
    };
  }
}

function getServerHealth(): SystemHealth['server'] {
  const uptime = process.uptime();
  const memUsage = process.memoryUsage();
  const totalMem = os.totalmem();
  const freeMem = os.freemem();
  const usedMem = totalMem - freeMem;
  const memPercentage = Math.round((usedMem / totalMem) * 100);
  
  // Calculate average response time from recent metrics
  const recentMetrics = performanceMetrics.slice(-100);
  const avgResponseTime = recentMetrics.length > 0 
    ? Math.round(recentMetrics.reduce((sum, m) => sum + m.responseTime, 0) / recentMetrics.length)
    : 0;
  
  // Simple CPU usage estimation (not accurate but provides indication)
  const cpuUsage = Math.round(Math.random() * 20 + 10); // Placeholder - would need proper CPU monitoring
  
  return {
    status: memPercentage < 80 && avgResponseTime < 500 ? "healthy" : memPercentage < 90 ? "warning" : "error",
    uptime,
    memory: {
      used: usedMem,
      total: totalMem,
      percentage: memPercentage
    },
    cpu: {
      usage: cpuUsage,
      cores: os.cpus().length
    },
    responseTime: avgResponseTime
  };
}

function getAuthenticationHealth(): SystemHealth['authentication'] {
  // Count recent failed attempts
  const recentFailures = errorLogs.filter(log => 
    log.message.includes('Invalid email or password') && 
    Date.now() - new Date(log.timestamp).getTime() < 3600000 // Last hour
  ).length;
  
  // Estimate active sessions (simplified)
  const recentActivity = performanceMetrics.filter(m => 
    Date.now() - new Date(m.timestamp).getTime() < 1800000 // Last 30 minutes
  );
  const uniqueIPs = new Set(recentActivity.map(m => m.ip)).size;
  
  const lastLoginTime = performanceMetrics
    .filter(m => m.path === '/api/auth/login' && m.statusCode === 200)
    .slice(-1)[0]?.timestamp || new Date().toISOString();
  
  return {
    status: recentFailures < 10 ? "healthy" : recentFailures < 50 ? "warning" : "error",
    activeSessions: uniqueIPs,
    failedAttempts: recentFailures,
    lastLogin: lastLoginTime
  };
}

function getApiHealth(): SystemHealth['api'] {
  const endpoints = [
    '/api/auth/user',
    '/api/auth/login',
    '/api/teams',
    '/api/players',
    '/api/coaches',
    '/api/dashboard/widgets',
    '/api/onboarding/smart-recommendations'
  ];
  
  return {
    endpoints: endpoints.map(endpoint => {
      const recentCalls = performanceMetrics.filter(m => m.path === endpoint).slice(-5);
      const avgResponseTime = recentCalls.length > 0 
        ? Math.round(recentCalls.reduce((sum, m) => sum + m.responseTime, 0) / recentCalls.length)
        : 0;
      const hasErrors = recentCalls.some(m => m.statusCode >= 400);
      const lastCall = recentCalls.slice(-1)[0];
      
      return {
        path: endpoint,
        method: 'GET',
        status: !hasErrors && avgResponseTime < 1000 ? "healthy" : "error",
        responseTime: avgResponseTime,
        lastChecked: lastCall?.timestamp || new Date().toISOString()
      };
    })
  };
}

// Helper function to check if user is admin
function requireAdmin(req: any, res: any, next: any) {
  if (!req.user) {
    return res.status(401).json({ message: "Not authenticated" });
  }
  if (req.user.role !== 'admin' && req.user.role !== 'superadmin') {
    return res.status(403).json({ message: "Admin access required" });
  }
  next();
}

export function registerDebugRoutes(app: Express) {
  // System health endpoint - protected, admin only
  app.get("/api/debug/system-health", requireAuth, requireAdmin, async (req: Request, res: Response) => {
    try {
      const systemHealth: SystemHealth = {
        database: await checkDatabaseHealth(),
        server: getServerHealth(),
        authentication: getAuthenticationHealth(),
        api: getApiHealth()
      };
      
      res.json(systemHealth);
    } catch (error) {
      addErrorLog({
        level: "error",
        message: "Failed to get system health",
        stack: (error as Error).stack,
        route: req.path
      });
      res.status(500).json({ error: "Failed to get system health" });
    }
  });
  
  // Error logs endpoint - protected, admin only
  app.get("/api/debug/error-logs", requireAuth, requireAdmin, (req: Request, res: Response) => {
    const limit = parseInt(req.query.limit as string) || 50;
    const level = req.query.level as string;
    
    let logs = errorLogs.slice(-limit).reverse();
    
    if (level) {
      logs = logs.filter(log => log.level === level);
    }
    
    res.json(logs);
  });
  
  // Performance metrics endpoint - protected, admin only
  app.get("/api/debug/performance", requireAuth, requireAdmin, (req: Request, res: Response) => {
    const limit = parseInt(req.query.limit as string) || 100;
    const metrics = performanceMetrics.slice(-limit);
    
    // Calculate aggregated metrics
    const avgResponseTime = metrics.length > 0 
      ? Math.round(metrics.reduce((sum, m) => sum + m.responseTime, 0) / metrics.length)
      : 0;
    
    const errorRate = metrics.length > 0 
      ? Math.round((metrics.filter(m => m.statusCode >= 400).length / metrics.length) * 100)
      : 0;
    
    const requestsPerMinute = metrics.filter(m => 
      Date.now() - new Date(m.timestamp).getTime() < 60000
    ).length;
    
    res.json({
      aggregated: {
        avgResponseTime,
        errorRate,
        requestsPerMinute,
        totalRequests: metrics.length
      },
      recent: metrics.slice(-20)
    });
  });
  
  // Download logs endpoint - protected, admin only
  app.get("/api/debug/download-logs", requireAuth, requireAdmin, (req: Request, res: Response) => {
    const exportData = {
      timestamp: new Date().toISOString(),
      errorLogs: errorLogs.slice(-500),
      performanceMetrics: performanceMetrics.slice(-1000),
      systemInfo: {
        nodeVersion: process.version,
        platform: os.platform(),
        arch: os.arch(),
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        cpu: os.cpus().length
      }
    };
    
    res.setHeader('Content-Type', 'application/json');
    res.setHeader('Content-Disposition', `attachment; filename="system-logs-${new Date().toISOString().split('T')[0]}.json"`);
    res.json(exportData);
  });
  
  // Test endpoint for debugging - protected, admin only
  app.post("/api/debug/test-error", requireAuth, requireAdmin, (req: Request, res: Response) => {
    const { type = "error", message = "Test error message" } = req.body;
    
    if (type === "error") {
      throw new Error(message);
    } else {
      addErrorLog({
        level: type as "warning" | "info",
        message,
        route: req.path
      });
      res.json({ message: "Test log added" });
    }
  });
  
  // Clear logs endpoint (development only) - protected, admin only
  app.delete("/api/debug/logs", requireAuth, requireAdmin, (req: Request, res: Response) => {
    if (process.env.NODE_ENV !== 'development') {
      return res.status(403).json({ error: "Only available in development" });
    }
    
    errorLogs.length = 0;
    performanceMetrics.length = 0;
    res.json({ message: "Logs cleared" });
  });
}