import { createApp } from './src/app.js';
import {
  ensureSchema,
  disableGuestsFromYesterday,
  getActiveSessions,
  markStaleSessions,
  syncConnectedDevicesFromSessions,
  cleanOldSessions
} from './src/services/db.js';
import { activeSessions } from './src/services/radius.js';
import { broadcastStatus } from './src/sse.js';

const app = createApp();
const port = process.env.PORT || 3000;

// Configuration from environment
const STALE_CHECK_INTERVAL = parseInt(process.env.STALE_CHECK_INTERVAL || '120000', 10); // 2 min
const MAX_IDLE_MINUTES = parseInt(process.env.MAX_IDLE_MINUTES || '10', 10);
const SESSION_HISTORY_RETENTION_DAYS = parseInt(process.env.SESSION_HISTORY_RETENTION_DAYS || '90', 10);

try {
  await ensureSchema();
} catch (e) {
  console.error('Database schema ensure failed:', e?.message || e);
}

// Initialize sessions from database on startup
async function initializeSessionsFromDb() {
  try {
    // Sync dispositivos_conectados from active sessions
    await syncConnectedDevicesFromSessions();

    // Load active sessions into memory Map for CoA
    const active = await getActiveSessions();
    for (const sess of active) {
      activeSessions.set(sess.session_id, {
        username: sess.username,
        sessionId: sess.session_id,
        nasIp: sess.nas_ip,
        nasId: sess.nas_id,
        callingStationId: sess.calling_station_id,
        calledStationId: sess.called_station_id,
        updatedAt: new Date(sess.last_update).getTime(),
      });
    }
    console.log(`[init] Loaded ${active.length} active sessions from database`);
  } catch (e) {
    console.error('[init] Failed to load sessions:', e?.message || e);
  }
}

// Job to detect and mark stale sessions
function scheduleStaleSessionsJob() {
  setInterval(async () => {
    try {
      const result = await markStaleSessions(MAX_IDLE_MINUTES);
      if (result.count > 0) {
        console.log(`[stale-sessions] Marked ${result.count} sessions as stale`);
        // Remove stale sessions from memory Map
        for (const sess of result.sessions) {
          activeSessions.delete(sess.session_id);
        }
        // Notify SSE clients
        broadcastStatus({ type: 'sessions-updated', staleCount: result.count });
      }
    } catch (e) {
      console.error('[stale-sessions] Error:', e?.message || e);
    }
  }, STALE_CHECK_INTERVAL);
}

// Job to clean old sessions (runs daily at 3:00 AM local)
function scheduleSessionCleanupJob() {
  function schedule() {
    const now = new Date();
    const next = new Date(now);
    next.setUTCHours(9, 0, 0, 0); // 9:00 UTC = 3:00 AM Honduras (UTC-6)
    if (next <= now) next.setUTCDate(next.getUTCDate() + 1);
    const delay = next - now;

    setTimeout(async () => {
      try {
        const deleted = await cleanOldSessions(SESSION_HISTORY_RETENTION_DAYS);
        if (deleted > 0) {
          console.log(`[session-cleanup] Deleted ${deleted} old sessions (>${SESSION_HISTORY_RETENTION_DAYS} days)`);
        }
      } catch (e) {
        console.error('[session-cleanup] Error:', e?.message || e);
      } finally {
        schedule(); // Re-schedule for tomorrow
      }
    }, delay);
  }
  schedule();
}

// Initialize sessions from database
try {
  await initializeSessionsFromDb();
} catch (e) {
  console.error('Session initialization failed:', e?.message || e);
}

// Start maintenance jobs
scheduleStaleSessionsJob();
scheduleSessionCleanupJob();

app.listen(port, () => {
  console.log(`Node RADIUS REST API listening on :${port}`);
  console.log(`[config] Stale check: every ${STALE_CHECK_INTERVAL/1000}s, idle timeout: ${MAX_IDLE_MINUTES} min, retention: ${SESSION_HISTORY_RETENTION_DAYS} days`);
});

// Schedule daily guest disable at 4:00 AM America/Tegucigalpa (UTC-6 -> 10:00 UTC)
function scheduleGuestJob() {
  const now = new Date();
  const next = new Date(now);
  next.setUTCHours(10, 0, 0, 0); // 10:00 UTC == 4:00 local (UTC-6)
  if (next <= now) next.setUTCDate(next.getUTCDate() + 1);
  const delay = next - now;
  setTimeout(async function run() {
    try {
      const { count } = await disableGuestsFromYesterday();
      if (count) console.log(`[guest-cron] Disabled ${count} invitado users from yesterday`);
    } catch (e) {
      console.error('[guest-cron] Error:', e?.message || e);
    } finally {
      scheduleGuestJob();
    }
  }, delay);
}

scheduleGuestJob();
