import 'dotenv/config';

import http from 'http';
import path from 'path';
import { existsSync } from 'fs';
import express from 'express';
import { WebSocket, WebSocketServer } from 'ws';
import { fileURLToPath } from 'url';

import { eventBus } from './lib/eventBus.js';
import { requireSession } from './lib/session.js';
import sessionRouter from './routes/session.js';
import stateRouter from './routes/state.js';
import ticketsRouter from './routes/tickets.js';
import mailRouter from './routes/mail.js';
import docsRouter from './routes/docs.js';
import vmsRouter from './routes/vms.js';
import sageRouter from './routes/sage.js';
import profileRouter from './routes/profile.js';
import debugRouter from './routes/debug.js';
import { contentLoader } from './services/ContentLoader.js';
import { saveState } from './services/SaveState.js';
import { progressionSystem } from './services/ProgressionSystem.js';
import { trustSystem } from './services/TrustSystem.js';
import { questEngine } from './services/QuestEngine.js';
import { ticketService } from './services/TicketService.js';
import { emailService } from './services/EmailService.js';
import { vmManager } from './services/VMManager.js';
import { shiftTimer } from './services/ShiftTimer.js';
import { incidentScheduler } from './services/IncidentScheduler.js';
import { shiftReviewService } from './services/ShiftReviewService.js';
import { certificationService } from './services/CertificationService.js';
import { behaviorTracker } from './services/BehaviorTracker.js';
import { narrativePhaseTracker } from './services/NarrativePhaseTracker.js';
import { hiddenHookTracker } from './services/HiddenHookTracker.js';
import { endingEvaluator } from './services/EndingEvaluator.js';

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

export async function initializeServices() {
  try {
    await contentLoader.load();
  } catch (error) {
    throw new Error(`Failed to load content: ${error.message}`);
  }

  try {
    await saveState.load();
  } catch (error) {
    throw new Error(`Failed to load save state: ${error.message}`);
  }

  const state = saveState.get();

  progressionSystem.initialize(state);
  trustSystem.initialize(state);
  behaviorTracker.initialize(state);
  questEngine.initialize(state);
  narrativePhaseTracker.initialize(state);
  hiddenHookTracker.initialize(state);
  ticketService.initialize(state);
  emailService.initialize(state);
  shiftReviewService.initialize(state);
  certificationService.initialize(state);
  shiftTimer.start(state);
  incidentScheduler.start();
  eventBus.on('quest:completed', () => { endingEvaluator.checkTrigger(); });

  try {
    const workstationStatus = await vmManager.ensureWorkstationLive();
    if (!workstationStatus.ok) {
      console.warn('Workstation VM not ready at bootstrap:', workstationStatus.reason ?? workstationStatus);
    }
  } catch (error) {
    console.warn('Failed to ensure workstation VM is live:', error.message);
  }
}

export function createApp() {
  const app = express();
  app.use(express.json());

  // Sage KB — static site + article API, no session required
  const sageStatic = path.resolve(__dirname, '../../sage');
  const sageArticles = path.resolve(__dirname, '../../content/sage-articles');
  const sendSageIndex = (_req, res) => res.sendFile(path.join(sageStatic, 'index.html'));
  app.use('/sage/api', express.static(sageArticles, { index: false }));
  app.use('/sage', express.static(sageStatic));
  app.get(['/sage', '/sage/'], sendSageIndex);

  // Company website — publicly accessible, no session required
  const companyWebsite = path.resolve(__dirname, '../../company-website');
  app.use('/company', express.static(companyWebsite));
  app.get(['/company', '/company/'], (_req, res) => res.sendFile(path.join(companyWebsite, 'index.html')));

  // Public assets — portraits, wallpaper
  const publicDir = path.resolve(__dirname, '../public');
  app.use('/public', express.static(publicDir));

  app.use('/api/session', sessionRouter);
  app.use('/api', requireSession);
  app.use('/api/state', stateRouter);
  app.use('/api/tickets', ticketsRouter);
  app.use('/api/mail', mailRouter);
  app.use('/api/docs', docsRouter);
  app.use('/api/vms', vmsRouter);
  app.use('/api/sage', sageRouter);
  app.use('/api/profile', profileRouter);
  if (process.env.SC_DEBUG === '1') {
    app.use('/api/debug', debugRouter);
  }

  const frontendDist = path.resolve(__dirname, '../../frontend/dist');
  const hasFrontendDist = existsSync(frontendDist);

  if (hasFrontendDist) {
    app.use(express.static(frontendDist));
  } else {
    app.get('/', (_req, res) => {
      res.status(200).json({ status: 'game server running', version: '0.1.0' });
    });
  }

  return app;
}

export function attachWebSocket(server) {
  const wss = new WebSocketServer({ server });

  wss.on('connection', (socket) => {
    socket.send(
      JSON.stringify({
        type: 'connected',
        payload: { trust: trustSystem.getScore() }
      })
    );
  });

  const forwardEvent = (eventName) => {
    eventBus.on(eventName, (payload) => {
      const message = JSON.stringify({ type: eventName, payload });

      for (const client of wss.clients) {
        if (client.readyState === WebSocket.OPEN) {
          client.send(message);
        }
      }
    });
  };

  for (const eventName of [
    'trust:changed',
    'mail:new',
    'progression:changed',
    'quest:activated',
    'quest:completed',
    'ticket:activated',
    'ticket:completed',
    'shift:tick',
    'shift:ended',
    'incident:alert',
    'certification:awarded'
  ]) {
    forwardEvent(eventName);
  }

  return { server, wss };
}

export async function startServer({ port = Number(process.env.PORT ?? 3000), host = '0.0.0.0' } = {}) {
  await initializeServices();
  const app = createApp();

  let server;
  const tlsCert = process.env.SC_TLS_CERT;
  const tlsKey = process.env.SC_TLS_KEY;

  if (tlsCert && tlsKey && existsSync(tlsCert) && existsSync(tlsKey)) {
    const { createServer: createHttpsServer } = await import('https');
    const { readFileSync } = await import('fs');
    server = createHttpsServer(
      { cert: readFileSync(tlsCert), key: readFileSync(tlsKey) },
      app
    );
  } else {
    server = http.createServer(app);
  }

  const { wss } = attachWebSocket(server);

  await new Promise((resolve) => {
    server.listen(port, host, resolve);
  });

  const proto = (tlsCert && tlsKey && existsSync(tlsCert) && existsSync(tlsKey)) ? 'https' : 'http';
  return { app, server, wss, proto };
}

if (process.argv[1] && path.resolve(process.argv[1]) === __filename) {
  startServer()
    .then(({ server }) => {
      const address = server.address();
      const actualPort = typeof address === 'object' && address ? address.port : process.env.PORT ?? 3000;
      console.log(`Game server running on port ${actualPort}`);
    })
    .catch((error) => {
      console.error(error.message);
      process.exit(1);
    });
}
