import express from 'express';
import { createServer } from 'http';
import { Server as SocketIOServer } from 'socket.io';
import cors from 'cors';
import path from 'path';
import { fileURLToPath } from 'url';

import { PerformanceMonitor } from '../utils/performance-monitor.js';
import { SecurityManager } from '../utils/security-manager.js';
import { ErrorHandler } from '../utils/error-handler.js';
import { setupMetricsAPI } from './api/metrics.js';
import { setupAgileAPI } from './api/agile.js';
import { setupSecurityAPI } from './api/security.js';
import { setupErrorsAPI } from './api/errors.js';
import { setupApprovalsAPI } from './api/approvals.js';
import { setupWebSocketHandlers } from './utils/websocket.js';
import { ensureDatabaseReady } from '../storage/sqlite-manager.js';
import { setSocketIOInstance } from './utils/database-events.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export interface DashboardConfig {
  enabled?: boolean;
  port?: number;
  host?: string;
  autoOpen?: boolean;
  features?: {
    performance?: boolean;
    security?: boolean;
    agile?: boolean;
    errors?: boolean;
  };
  realTimeUpdates?: boolean;
  exportEnabled?: boolean;
}

export class DashboardServer {
  private app: express.Application;
  private server: any;
  private io: SocketIOServer;
  private config: DashboardConfig;
  private isRunning: boolean = false;

  constructor(
    config: DashboardConfig,
    private performanceMonitor: PerformanceMonitor,
    private securityManager: SecurityManager,
    private errorHandler: ErrorHandler,
    private agileManager?: any
  ) {
    this.config = config;
    this.app = express();
    this.server = createServer(this.app);
    this.io = new SocketIOServer(this.server, {
      cors: {
        origin: `http://${config.host}:${config.port}`,
        methods: ['GET', 'POST']
      }
    });

    this.setupMiddleware();
    this.setupRoutes();
    this.setupStaticFiles();
    this.setupWebSocket();
  }

  private setupMiddleware(): void {
    this.app.use(cors());
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));

    // Request logging middleware - only log API errors
    this.app.use((req, res, next) => {
      // Skip logging for static file requests
      if (!req.path.startsWith('/api/')) {
        return next();
      }
      
      // Store the original res.json to intercept responses
      const originalJson = res.json;
      res.json = function(data) {
        // Only log if there's an error or non-2xx status
        if (res.statusCode >= 400 || (data && data.error)) {
          console.error(`📊 Dashboard API Error: ${req.method} ${req.path} - Status: ${res.statusCode}`);
        }
        return originalJson.call(this, data);
      };
      next();
    });
  }

  private setupStaticFiles(): void {
    // Serve static files from public directory
    const publicPath = path.join(__dirname, 'public');
    this.app.use(express.static(publicPath));
    
    // Serve main dashboard page
    this.app.get('/', (req, res) => {
      res.sendFile(path.join(publicPath, 'index.html'));
    });
  }

  private setupRoutes(): void {
    // API Routes
    if (this.config.features.performance) {
      setupMetricsAPI(this.app, this.performanceMonitor, this.config.exportEnabled);
    }

    if (this.config.features.agile && this.agileManager) {
      setupAgileAPI(this.app, this.agileManager);
      // Add advanced agile analytics routes
      import('./api/agile-analytics.js').then(module => {
        this.app.use('/api/agile', module.default);
      }).catch(err => {
        console.error('Failed to load agile analytics API:', err);
      });
    }

    if (this.config.features.security) {
      setupSecurityAPI(this.app, this.securityManager);
    }

    if (this.config.features.errors) {
      setupErrorsAPI(this.app, this.errorHandler);
    }

    // Always enable approvals API for human interaction
    setupApprovalsAPI(this.app);

    // Health check endpoint
    this.app.get('/api/health', async (req, res) => {
      try {
        const db = await ensureDatabaseReady(1, 100); // Quick check
        const dbInfo = db.getConnectionInfo();
        
        res.json({
          status: 'healthy',
          timestamp: new Date().toISOString(),
          features: this.config.features,
          version: process.env.npm_package_version || '1.0.0',
          database: {
            status: dbInfo.isInitialized ? 'ready' : 'not_ready',
            path: dbInfo.dbPath
          }
        });
      } catch (error) {
        res.status(503).json({
          status: 'unhealthy',
          timestamp: new Date().toISOString(),
          error: 'Database not available',
          database: {
            status: 'not_ready'
          }
        });
      }
    });

    // 404 handler for API routes
    this.app.use('/api/*', (req, res) => {
      res.status(404).json({
        error: 'API endpoint not found',
        path: req.path,
        method: req.method
      });
    });
  }

  private setupWebSocket(): void {
    if (this.config.realTimeUpdates) {
      // Set Socket.IO instance for database events
      setSocketIOInstance(this.io);
      
      setupWebSocketHandlers(
        this.io,
        this.performanceMonitor,
        this.securityManager,
        this.errorHandler,
        this.agileManager
      );
    }
  }

  async start(): Promise<void> {
    if (this.isRunning) {
      console.error('📊 Dashboard server is already running');
      return;
    }

    // Wait for database to be ready before starting the server
    try {
      console.error('📊 Waiting for database to be ready...');
      await ensureDatabaseReady(5, 2000); // 5 retries, 2s delay each
      console.error('✅ Database is ready for dashboard');
    } catch (error) {
      console.error('❌ Database not ready for dashboard:', error);
      throw error;
    }

    return new Promise((resolve, reject) => {
      this.server.listen(this.config.port, this.config.host, () => {
        this.isRunning = true;
        const url = `http://${this.config.host}:${this.config.port}`;
        console.error(`📊 Atlas Dashboard available at ${url}`);
        
        if (this.config.realTimeUpdates) {
          console.error('📡 Real-time updates enabled via WebSocket');
        }

        // Start real-time data collection
        this.startDataCollection();
        
        resolve();
      });

      this.server.on('error', (error: any) => {
        if (error.code === 'EADDRINUSE') {
          console.error(`❌ Dashboard port ${this.config.port} is already in use`);
          console.error(`💡 Try changing the port in your Atlas configuration`);
        } else {
          console.error(`❌ Dashboard server error:`, error.message);
        }
        reject(error);
      });
    });
  }

  async stop(): Promise<void> {
    if (!this.isRunning) {
      return;
    }

    return new Promise((resolve) => {
      this.stopDataCollection();
      
      // Close all socket.io connections first
      this.io.close(() => {
        // Then close the HTTP server
        this.server.close(() => {
          this.isRunning = false;
          console.error('📊 Dashboard server stopped');
          resolve();
        });
      });
      
      // Force close any remaining connections after a timeout
      setTimeout(() => {
        this.server.closeAllConnections?.();
        resolve();
      }, 1000);
    });
  }

  private dataCollectionInterval?: NodeJS.Timeout;

  private startDataCollection(): void {
    if (!this.config.realTimeUpdates) {
      return;
    }

    // Collect and broadcast data every 5 seconds
    this.dataCollectionInterval = setInterval(async () => {
      try {
        // Broadcast performance metrics
        if (this.config.features.performance) {
          const metrics = await this.performanceMonitor.getSystemMetrics();
          this.io.emit('performance_update', {
            timestamp: new Date().toISOString(),
            metrics
          });
        }

        // Broadcast security status
        if (this.config.features.security) {
          const securityStatus = await this.securityManager.getSecurityStatus();
          this.io.emit('security_update', {
            timestamp: new Date().toISOString(),
            status: securityStatus
          });
        }

        // Broadcast error patterns (less frequent - every 30 seconds)
        if (this.config.features.errors && Math.random() < 0.16) { // ~1/6 chance = every 30s
          const errorPatterns = await this.errorHandler.analyzeErrorPatterns({
            timeRange: '1h',
            minOccurrences: 1,
            groupBy: 'type'
          });
          this.io.emit('errors_update', {
            timestamp: new Date().toISOString(),
            patterns: errorPatterns
          });
        }

      } catch (error) {
        console.error('📊 Dashboard data collection error:', error);
      }
    }, 5000);
  }

  private stopDataCollection(): void {
    if (this.dataCollectionInterval) {
      clearInterval(this.dataCollectionInterval);
      this.dataCollectionInterval = undefined;
    }
  }

  getUrl(): string {
    return `http://${this.config.host}:${this.config.port}`;
  }

  isHealthy(): boolean {
    return this.isRunning;
  }

  getConfig(): DashboardConfig {
    return { ...this.config };
  }
}