const express = require('express');
const http = require('http');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
require('dotenv').config();

const { initializeDatabase } = require('./db/seed');
const { errorHandler, notFoundHandler } = require('./middleware/errorHandler');

// Import routes
const authRoutes = require('./routes/auth.routes');
const userRoutes = require('./routes/user.routes');
const fidoKeyRoutes = require('./routes/fidoKey.routes');
const assetRoutes = require('./routes/asset.routes');
const onboardingRoutes = require('./routes/onboarding.routes');
const offboardingRoutes = require('./routes/offboarding.routes');
const ticketRoutes = require('./routes/ticket.routes');
const microsoftAuthRoutes = require('./routes/microsoft.auth.routes');
const licenseRoutes = require('./routes/license.routes');
const aiRoutes = require('./routes/ai.routes');
const botRoutes = require('./routes/bot.routes');
const settingsRoutes = require('./routes/settings.routes');
const onboardingProcessRoutes = require('./routes/onboardingProcess.routes');
const itTopicRoutes = require('./routes/itTopic.routes');
const isoTaskRoutes = require('./routes/isoTask.routes');
const riskRoutes    = require('./routes/risk.routes');
const entraRoutes   = require('./routes/entra.routes');
const monitoringRoutes = require('./routes/monitoringAgent.routes');
const teamsActivityRoutes = require('./routes/teamsActivity.routes');
const scannerRoutes = require('./routes/scanner.routes');

const app = express();
const PORT = process.env.PORT || 5000;

// Trust reverse proxy (NPM/nginx) - required for rate limiting behind proxy
app.set('trust proxy', 1);

// ============================================================================
// MIDDLEWARE
// ============================================================================

// Security headers
app.use(helmet());

// CORS configuration
app.use(cors({
    origin: process.env.NODE_ENV === 'development'
        ? '*' // Development: Allow all origins (for mobile app testing)
        : [process.env.FRONTEND_URL || 'http://localhost:3000', process.env.MOBILE_APP_URL],
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization']
}));

// Body parsing (50 MB for file uploads via base64)
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));

// Logging in development
if (process.env.NODE_ENV === 'development') {
    app.use(morgan('dev'));
}

// Rate limiting for auth endpoints
const authLimiter = rateLimit({
    windowMs: parseInt(process.env.RATE_LIMIT_WINDOW) * 60 * 1000 || 15 * 60 * 1000, // 15 minutes
    max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100,
    message: {
        status: 'error',
        message: 'Too many requests, please try again later'
    },
    standardHeaders: true,
    legacyHeaders: false
});

// ============================================================================
// ROUTES
// ============================================================================

// Health check
app.get('/health', (req, res) => {
    res.json({
        status: 'success',
        message: 'Server is running',
        timestamp: new Date().toISOString()
    });
});

// Health history – 90 Tage aggregiert (public, kein Auth nötig)
app.get('/api/health/history', (req, res) => {
    try {
        const { getDatabase } = require('./config/database');
        const db = getDatabase();
        const rows = db.prepare(`
            SELECT
                date(checked_at) as day,
                SUM(CASE WHEN api_status = 'error' OR db_status = 'error' THEN 1 ELSE 0 END) as errors,
                SUM(CASE WHEN api_status = 'warn' OR db_status = 'warn' THEN 1 ELSE 0 END) as warns,
                COUNT(*) as total
            FROM health_history
            WHERE checked_at >= date('now', '-90 days')
            GROUP BY date(checked_at)
            ORDER BY day ASC
        `).all();

        // Alle 90 Tage generieren (Lücken = down)
        const days = [];
        for (let i = 89; i >= 0; i--) {
            const d = new Date();
            d.setDate(d.getDate() - i);
            const dayStr = d.toISOString().slice(0, 10);
            const row = rows.find(r => r.day === dayStr);
            if (!row) {
                // Heute oder kein Eintrag vorhanden – heute = ok wenn Backend läuft
                days.push({ day: dayStr, status: i === 0 ? 'ok' : 'error' });
            } else {
                const status = row.errors > 0 ? 'error' : row.warns > 0 ? 'warn' : 'ok';
                days.push({ day: dayStr, status });
            }
        }
        res.json(days);
    } catch (e) {
        res.json([]);
    }
});

// API routes
app.use('/api/auth', authLimiter, authRoutes);
app.use('/api/users', userRoutes);
app.use('/api/fido-keys', fidoKeyRoutes);
app.use('/api/assets', assetRoutes);
app.use('/api/onboarding', onboardingRoutes);
app.use('/api/offboarding', offboardingRoutes);
app.use('/api/tickets', ticketRoutes);
app.use('/api/auth/microsoft', microsoftAuthRoutes);
app.use('/api/licenses', licenseRoutes);
app.use('/api/ai', aiRoutes);
app.use('/api/bot', botRoutes);
app.use('/api/settings', settingsRoutes);
app.use('/api/onboarding-processes', onboardingProcessRoutes);
app.use('/api/it-topics', itTopicRoutes);
app.use('/api/iso-tasks', isoTaskRoutes);
app.use('/api/risks',    riskRoutes);
app.use('/api/entra',    entraRoutes);
app.use('/api/monitoring', monitoringRoutes);
app.use('/api/scanner', scannerRoutes);

const networkMonitorRoutes = require('./routes/networkMonitor.routes');
app.use('/api/network-monitor', networkMonitorRoutes);
app.use('/api/teams-activity', teamsActivityRoutes);
const unifiRoutes = require('./routes/unifi.routes');
app.use('/api/unifi', unifiRoutes);
const externalAlertRoutes = require('./routes/externalAlert.routes');
app.use('/api/external-alerts', externalAlertRoutes);
const warehouseRoutes = require('./routes/warehouse.routes');
app.use('/api/warehouse', warehouseRoutes);
const assetTypeRoutes = require('./routes/assetType.routes');
app.use('/api/asset-types', assetTypeRoutes);
const portalGuideRoutes = require('./routes/portalGuide.routes');
app.use('/api/portal-guides', portalGuideRoutes);
const patchRoutes = require('./routes/patch.routes');
app.use('/api/patch', patchRoutes);
const proxmoxRoutes = require('./routes/proxmox.routes');
app.use('/api/proxmox', proxmoxRoutes);
const dockerRoutes = require('./routes/docker.routes');
app.use('/api/docker', dockerRoutes);
const announcementRoutes = require('./routes/announcement.routes');
app.use('/api/announcements', announcementRoutes);
const knowledgeRoutes = require('./routes/knowledge.routes');
app.use('/api/knowledge', knowledgeRoutes);
const shareRoutes = require('./routes/share.routes');
app.use('/api/shares', shareRoutes);
const securityReportRoutes = require('./routes/securityReport.routes');
app.use('/api/security-reports', securityReportRoutes);
const tvRoutes = require('./routes/tv.routes');
app.use('/api/tv', tvRoutes);
const feedbackRoutes = require('./routes/feedback.routes');
app.use('/api/feedback', feedbackRoutes);
const cronRoutes = require('./routes/cron.routes');
app.use('/api/cron', cronRoutes);
const licensePriceRoutes = require('./routes/licensePrice.routes');
app.use('/api/license-prices', licensePriceRoutes);

// Static file serving for uploads (PDFs)
const path = require('path');
app.use('/uploads', express.static(path.join(__dirname, '../uploads')));

// Agent downloads (installer, intunewin)
app.use('/downloads', express.static(path.join(__dirname, '../downloads')));


// 404 handler
app.use(notFoundHandler);

// Global error handler
app.use(errorHandler);

// ============================================================================
// SERVER INITIALIZATION
// ============================================================================

async function startServer() {
    try {
        // Initialize database
        console.log('🚀 Starting IT Nexus - by Simon Grüßing...');
        console.log('');

        await initializeDatabase();

        // Migrate ticket settings (categories + templates)
        const TicketSettings = require('./models/TicketSettings');
        TicketSettings.migrate();
        console.log('✅ Ticket settings (categories/templates) ready');

        // Migrate email templates
        const { EmailTemplate } = require('./models/EmailTemplate');
        EmailTemplate.migrate();
        console.log('✅ Email templates ready');

        // Migrate email design
        const { EmailDesign } = require('./models/EmailDesign');
        EmailDesign.migrate();
        console.log('✅ Email design ready');

        // Migrate onboarding process templates
        const OnboardingProcess = require('./models/OnboardingProcess');
        OnboardingProcess.migrate();
        console.log('✅ Onboarding/Offboarding process templates ready');

        // Migrate IT topics
        const ItTopic = require('./models/ItTopic');
        ItTopic.migrate();
        console.log('✅ IT Übersicht topics ready');

        // Migrate asset inspections
        const AssetInspection = require('./models/AssetInspection');
        AssetInspection.migrate();
        console.log('✅ Asset inspections ready');

        // Migrate ISO tasks
        const IsoTask = require('./models/IsoTask');
        IsoTask.migrate();
        console.log('✅ ISO tasks ready');

        // Migrate risk assessment
        const Risk = require('./models/Risk');
        Risk.migrate();
        console.log('✅ Risk assessment ready');
        console.log('');

        // Start email polling (every 30 seconds)
        // Prefer Graph API if Azure is configured, fall back to IMAP
        const cron = require('node-cron');
        const EmailService = require('./services/email.service');

        if (process.env.AZURE_TENANT_ID && process.env.AZURE_CLIENT_ID) {
            const GraphService = require('./services/graph.service');
            cron.schedule('*/30 * * * * *', () => {
                GraphService.pollMailbox().catch(err => console.error('[Graph] Poll failed:', err.message));
            });
            console.log('📧 Graph API mail polling started (every 30 seconds)');

            // Monitoring-Postfach (nur Netgo-Alerts, keine Tickets)
            if (process.env.MONITORING_MAILBOX) {
                cron.schedule('*/30 * * * * *', () => {
                    GraphService.pollMonitoringMailbox().catch(err => console.error('[Graph/Monitoring] Poll failed:', err.message));
                });
                console.log(`📡 Monitoring-Postfach polling gestartet: ${process.env.MONITORING_MAILBOX}`);
            }

            // MDO (Microsoft Defender for Office 365) Alert Polling (alle 5 Minuten)
            let mdoPollRunning = false;
            cron.schedule('*/5 * * * *', () => {
                if (mdoPollRunning) return;
                mdoPollRunning = true;
                GraphService.pollMdoAlerts()
                    .catch(err => console.error('[MDO] Poll failed:', err.message))
                    .finally(() => { mdoPollRunning = false; });
            });
            console.log('🛡️  MDO Alert Polling gestartet (alle 5 Minuten)');
        } else if (process.env.IMAP_HOST) {
            cron.schedule('*/30 * * * * *', () => {
                EmailService.pollMailbox().catch(err => console.error('[IMAP] Poll failed:', err.message));
            });
            console.log('📧 IMAP polling started (every 30 seconds)');
        }

        // Planner Auto-Sync (alle 15 Minuten)
        if (process.env.PLANNER_PLAN_ID && process.env.AZURE_TENANT_ID && process.env.AZURE_CLIENT_ID) {
            const { syncItTopicsToPlanner } = require('./services/graph.service');
            const ItTopic = require('./models/ItTopic');
            let plannerSyncRunning = false;
            cron.schedule('*/10 * * * * *', () => {
                if (plannerSyncRunning) return; // skip if previous run not done
                plannerSyncRunning = true;
                const topics = ItTopic.getAll({});
                syncItTopicsToPlanner(topics, process.env.PLANNER_PLAN_ID)
                    .then(r => {
                        if (r.imported || r.pulled || r.created || r.updated)
                            console.log(`[Planner] Auto-Sync: +${r.imported} importiert, ${r.pulled} gezogen, ${r.created} erstellt, ${r.updated} aktualisiert`);
                    })
                    .catch(err => console.error('[Planner] Auto-Sync fehlgeschlagen:', err.message))
                    .finally(() => { plannerSyncRunning = false; });
            });
            console.log('📋 Planner Auto-Sync gestartet (alle 10 Sekunden)');
        }

        // Eskalations-Check (stündlich)
        cron.schedule('0 * * * *', () => {
            EmailService.runEscalationCheck().catch(err => console.error('[Escalation] Check failed:', err.message));
        });
        console.log('🚨 Eskalations-Check gestartet (stündlich)');

        // Shares-Cleanup: abgelaufene / verbrauchte Links löschen (alle 15 Minuten)
        const { cleanupExpired: cleanupShares } = require('./controllers/share.controller');
        cron.schedule('*/15 * * * *', cleanupShares);
        console.log('🔗 Shares-Cleanup gestartet (alle 15 Minuten)');

        // Mindestbestand-Check (täglich 07:00)
        cron.schedule('0 7 * * *', async () => {
            try {
                const StockThreshold = require('./models/StockThreshold');
                const violations = StockThreshold.getViolations();
                if (violations.length === 0) return;

                for (const v of violations) {
                    if (!v.notify_email) continue;
                    const subject = `[IT Nexus] ⚠️ Mindestbestand unterschritten: ${v.category}`;
                    const html = `
                        <h2>Mindestbestand-Warnung</h2>
                        <p>Die Kategorie <strong>${v.category}</strong> hat den Mindestbestand unterschritten.</p>
                        <table style="border-collapse:collapse">
                            <tr><td style="padding:4px 12px"><b>Kategorie</b></td><td>${v.category}</td></tr>
                            <tr><td style="padding:4px 12px"><b>Aktueller Bestand (verfügbar)</b></td><td>${v.current_stock}</td></tr>
                            <tr><td style="padding:4px 12px"><b>Mindestbestand</b></td><td>${v.min_stock}</td></tr>
                        </table>
                        <p><a href="${process.env.FRONTEND_URL}/warehouse">Zum Lager-Modul →</a></p>
                    `;
                    v.notify_email.split(',').forEach(email => {
                        EmailService.sendMail(email.trim(), subject, html).catch(() => {});
                    });
                }
                console.log(`[Lager] Mindestbestand-Check: ${violations.length} Verletzung(en) gemeldet`);
            } catch (err) {
                console.error('[Lager] Mindestbestand-Check fehlgeschlagen:', err.message);
            }
        });
        console.log('📦 Mindestbestand-Check gestartet (täglich 07:00)');

        // Health-History aufzeichnen (alle 5 Minuten)
        cron.schedule('*/5 * * * *', () => {
            try {
                const { getDatabase } = require('./config/database');
                const db = getDatabase();
                let dbS = 'ok';
                try { db.prepare('SELECT 1').get(); } catch { dbS = 'error'; }
                db.prepare('INSERT INTO health_history (api_status, db_status) VALUES (?, ?)').run('ok', dbS);
                // Alte Einträge löschen (älter als 100 Tage)
                db.prepare("DELETE FROM health_history WHERE checked_at < datetime('now', '-100 days')").run();
            } catch (_) {}
        });
        console.log('💚 Health-Monitoring gestartet (alle 5 Minuten)');

        // Wöchentlicher Bericht (Montag 08:00)
        cron.schedule('0 8 * * 1', () => {
            EmailService.sendWeeklyReport().catch(err => console.error('[Report] Weekly report failed:', err.message));
        });
        console.log('📊 Wöchentlicher Bericht konfiguriert (Montag 08:00)');

        // Tägliche Wartungs-Fälligkeits-Benachrichtigung (08:00)
        cron.schedule('0 8 * * *', () => {
            EmailService.sendMaintenanceDueNotifications().catch(err => console.error('[Maintenance] Notification failed:', err.message));
        });
        console.log('🔧 Wartungs-Benachrichtigungen konfiguriert (täglich 08:00)');

        // Netzwerk-Monitoring-Polling starten
        const { startPoller } = require('./services/networkPoller.service');
        startPoller((device, newStatus) => {
            // E-Mail-Alert bei Status-Wechsel
            if (!device.notify_email) return;
            const subject = newStatus === 'down'
                ? `[IT Nexus] ALARM: ${device.name} ist OFFLINE`
                : `[IT Nexus] ENTWARNUNG: ${device.name} ist wieder ONLINE`;
            const html = newStatus === 'down'
                ? `<p>Das Gerät <strong>${device.name}</strong> (${device.host}) antwortet nicht mehr.</p><p>Check-Typ: ${device.check_type.toUpperCase()}</p>`
                : `<p>Das Gerät <strong>${device.name}</strong> (${device.host}) ist wieder erreichbar.</p>`;
            device.notify_email.split(',').forEach(email => {
                EmailService.sendMail(email.trim(), subject, html).catch(() => {});
            });
        });

        // Unifi Controller Polling (deaktiviert)
        // const { startUnifiPoller } = require('./services/unifiService');
        // startUnifiPoller();

        // Teams Channel Polling (alle 10 Minuten)
        if (process.env.AZURE_TENANT_ID && process.env.AZURE_CLIENT_ID) {
            const { pollTeamsChannels, initialSync } = require('./services/teamsChannelPoller.service');
            initialSync().catch(err => console.error('[Teams] Initial sync error:', err.message));
            cron.schedule('*/10 * * * *', () => {
                pollTeamsChannels().catch(err => console.error('[Teams] Poll failed:', err.message));
            });
            console.log('💬 Teams Channel-Monitoring gestartet (alle 10 Minuten)');
        }

        // Cleanup alter Check-Historien (täglich 03:00)
        cron.schedule('0 3 * * *', () => {
            const NetworkDevice = require('./models/NetworkDevice');
            NetworkDevice.cleanupOldChecks();
        });

        // Proxmox Monitoring (alle 5 Minuten)
        if (process.env.PROXMOX_HOST && process.env.PROXMOX_TOKEN) {
            const { pollProxmox } = require('./services/proxmoxService');
            cron.schedule('*/5 * * * *', () => {
                pollProxmox().catch(err => console.error('[Proxmox] Poll failed:', err.message));
            });
            console.log('🖥️  Proxmox Monitoring gestartet (alle 5 Minuten)');
        }

        // Entra Profil-Sync (täglich 02:00 Uhr)
        if (process.env.AZURE_TENANT_ID && process.env.AZURE_CLIENT_ID) {
            const { syncEntraProfiles } = require('./services/entraSync.service');
            cron.schedule('0 2 * * *', async () => {
                console.log('[Cron] Entra Profil-Sync gestartet');
                try { await syncEntraProfiles(); } catch (e) { console.error('[Cron] Entra Sync Fehler:', e.message); }
            }, { timezone: 'Europe/Berlin' });
            console.log('👤 Entra Profil-Sync konfiguriert (täglich 02:00 Uhr)');
        }

        // Start server
        const { setupWebSocketServer } = require('./ws/shellServer');
        const httpServer = http.createServer(app);
        setupWebSocketServer(httpServer);

        httpServer.listen(PORT, () => {
            console.log('═══════════════════════════════════════════');
            console.log(`✅ Server running on http://localhost:${PORT}`);
            console.log(`📝 Environment: ${process.env.NODE_ENV || 'development'}`);
            console.log(`🌐 API: http://localhost:${PORT}/api`);
            console.log(`💚 Health: http://localhost:${PORT}/health`);
            console.log(`🔌 WebSocket: ws://localhost:${PORT}/ws`);
            console.log('═══════════════════════════════════════════');
            console.log('');
            console.log('Press CTRL+C to stop the server');
            console.log('');
        });
    } catch (error) {
        console.error('❌ Failed to start server:', error.message);
        process.exit(1);
    }
}

// Handle graceful shutdown
process.on('SIGINT', () => {
    console.log('\n\n👋 Shutting down gracefully...');
    process.exit(0);
});

process.on('SIGTERM', () => {
    console.log('\n\n👋 Shutting down gracefully...');
    process.exit(0);
});

// Start the server
startServer();

module.exports = app;
