require('./config/config');

// console.log(" lodash");

console.log('VERSIONE NODE.JS :', process.versions.node);
if (process.env.AUTH_MONGODB === undefined) {
  console.error("AUTH_MONGODB non presente. VARIABILI D'AMBIENTE NON SETTATI!");
  process.exit(1);
}

const _ = require('lodash');
// console.log(" cors");
const cors = require('cors');

// console.log(" 2) fs");
const fs = require('fs'); // 👈 Usa il modulo promises

var https = require('https');
var http = require('http');

const WebSocket = require('ws');
const { spawn } = require('child_process');

const helmet = require('helmet');
const morgan = require('morgan');
const apiRouter = require('./routes/index-aa');
const { notFound, errorHandler } = require('./middleware/error');
const rateLimit = require('./middleware/rateLimit').rateLimit;

const NUOVO_METODO_TEST = true;

const METODO_MULTI_CORS = true;

const server_constants = require('./tools/server_constants');

//const throttle = require('express-throttle-bandwidth');
// app.use(throttle(1024 * 128)) // throttling bandwidth

// var cookieParser = require('cookie-parser')
// var csrf = require('csurf')
const express = require('express');
const vhost = require('vhost');

const bodyParser = require('body-parser');
const path = require('path');

const cron = require('node-cron');
console.log('Starting mongoose...');

// console.log('Starting pem...');

// const pem = require('pem')

const { Settings } = require('./models/settings');

const Site = require('./models/site');

// test

const i18n = require('i18n');

const readline = require('readline');

let credentials = null;

console.log('DB: ' + process.env.DATABASE);
// console.log("PORT: " + port);
// console.log("MONGODB_URI: " + process.env.MONGODB_URI);

var app = express();

let telegrambot = null;

const tools = require('./tools/general');

const shared_consts = require('./tools/shared_nodejs');

const { connectToDatabase, connectionUrl, options } = require('./db/mongoose');

// Avvia la connessione
connectToDatabase(connectionUrl, options)
  .then(() => {
    console.log('------------------------------------------------------------------');
    console.log('---------------   CONNESSIONE AL DB EFFETTUATA ! -----------------');
    console.log('------------------------------------------------------------------');

    const { CfgServer } = require('./models/cfgserver');
    const { ObjectId } = require('mongodb');

    const populate = require('./populate/populate');
    const { Circuit } = require('./models/circuit');

    const printf = require('util').format;

    myLoad().then((ris) => {
      const { User } = require('./models/user');

      require('./models/todo');
      require('./models/project');
      require('./models/subscribers');
      require('./models/booking');
      require('./models/sendmsg');
      require('./models/sendnotif');
      require('./models/mailinglist');
      require('./models/newstosent');
      require('./models/mypage');
      require('./models/myelem');
      require('./models/myscheda');
      require('./models/bot');
      require('./models/calzoom');

      const mysql_func = require('./mysql/mysql_func');

      const index_router = require('./router/index_router');
      const push_router = require('./router/push_router');
      const newsletter_router = require('./router/newsletter_router');
      const booking_router = require('./router/booking_router');
      const dashboard_router = require('./router/dashboard_router');
      const myevent_router = require('./router/myevent_router');
      const subscribe_router = require('./router/subscribe_router');
      const sendmsg_router = require('./router/sendmsg_router');
      const sendnotif_router = require('./router/sendnotif_router');
      const email_router = require('./router/email_router');
      const todos_router = require('./router/todos_router');
      const test_router = require('./router/test_router');
      const projects_router = require('./router/projects_router');
      const report_router = require('./router/report_router');
      const users_router = require('./router/users_router');
      const reactions_router = require('./router/reactions_router');
      const mygroups_router = require('./router/mygroups_router');
      const circuits_router = require('./router/circuits_router');
      const accounts_router = require('./router/accounts_router');
      const iscrittiConacreis_router = require('./router/iscrittiConacreis_router');
      const iscrittiArcadei_router = require('./router/iscrittiArcadei_router');
      const site_router = require('./router/site_router');
      const admin_router = require('./router/admin_router');
      const products_router = require('./router/products_router');
      const myscraping_router = require('./router/myscraping_router');
      const catalogs_router = require('./router/catalogs_router');
      const cart_router = require('./router/cart_router');
      const orders_router = require('./router/orders_router');
      const city_router = require('./router/city_router');
      const myskills_router = require('./router/myskills_router');
      const mygoods_router = require('./router/mygoods_router');
      const mygen_router = require('./router/mygen_router');
      const aitools_router = require('./router/aitools_router');
      const article_router = require('./router/articleRoutes');
      const api_router = require('./router/api_router');
      const api2_router = require('./router/api2_router');

      const { MyEvent } = require('./models/myevent');

      app.use('/videos', express.static(path.join(__dirname, 'uploads/videos')));

      app.use(bodyParser.json({ limit: '50mb' }));
      app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));

      app.use(express.static('views'));

      app.use(express.json({ limit: '100mb' }));
      app.use(express.urlencoded({ extended: true, limit: '100mb' }));

      // app.use(express.static(path.join(__dirname, 'client')));

      app.use(bodyParser.json());

      // app.set('view engine', 'pug');

      // Set static folder
      // app.use(express.static(path.join(__dirname, 'public')));

      i18n.configure({
        locales: ['it', 'enUs', 'es', 'fr', 'pt', 'si'],
        defaultLocale: 'it',
        // cookie: 'cook',
        directory: __dirname + '/locales',
        api: {
          __: 'translate',
          __n: 'translateN',
        },
      });

      // Serve il tuo service worker da una certa directory
      /*app.get('/service-worker.js', (req, res) => {
        res.set('Cache-Control', 'no-cache'); // Aggiunge l'intestazione
        // res.sendFile(path.join(__dirname, 'service-worker.js')); // Modifica il percorso secondo la tua struttura
      });*/

      app.use(bodyParser.json());

      // app.use(express.cookieParser());
      app.use(i18n.init);

      console.log('Use Routes ...');

      // catch 404 and forward to error handler
      // app.use(function (req, res, next) {
      //   var err = new Error('Not Found');
      //   err.status = 404;
      //   next(err);
      // });

      // development error handler
      // will print stacktrace
      if (app.get('env') === 'development') {
        app.use(function (err, req, res, next) {
          console.log('Server Error: ', err.message);
          // console.trace();
          res.status(err.status || 500).send({ error: err.message });
          // res.render('error', {
          //   message: err.message,
          //   error: err
          // });
        });
      }
      if (process.env.NODE_ENV === 'production') {
        console.log('*** PRODUCTION! ');
      }

      startServer(app, process.env.PORT);

      // Use Routes
      app.use('/', index_router);
      app.use('/subscribe', subscribe_router);
      app.use('/sendmsg', sendmsg_router);
      app.use('/sendnotif', sendnotif_router);
      app.use('/push', push_router);
      app.use('/news', newsletter_router);
      app.use('/booking', booking_router);
      app.use('/dashboard', dashboard_router);
      app.use('/event', myevent_router);
      app.use('/email', email_router);
      app.use('/todos', todos_router);
      app.use('/test', test_router);
      app.use('/projects', projects_router);
      app.use('/users', users_router);
      app.use('/reactions', reactions_router);
      app.use('/mygroup', mygroups_router);
      app.use('/circuit', circuits_router);
      app.use('/account', accounts_router);
      app.use('/iscritti_conacreis', iscrittiConacreis_router);
      app.use('/iscritti_arcadei', iscrittiArcadei_router);
      app.use('/report', report_router);
      app.use('/site', site_router);
      app.use('/admin', admin_router);
      app.use('/products', products_router);
      app.use('/myscraping', myscraping_router);
      app.use('/catalogs', catalogs_router);
      app.use('/cart', cart_router);
      app.use('/orders', orders_router);
      app.use('/city', city_router);
      app.use('/myskills', myskills_router);
      app.use('/mygoods', mygoods_router);
      app.use('/mygen', mygen_router);
      app.use('/aitools', aitools_router);
      app.use('/apisqlsrv', article_router);
      app.use('/api', api_router);
      app.use('/api2', api2_router);

      mystart();
    });

    // app.use(throttle(1024 * 128)); // throttling bandwidth

    async function myLoad() {
      return tools.loadApps();
    }

    async function mystart() {
      // await estraiTutteLeImmagini();

      console.log('Versione Server: ' + (await tools.getVersServer()));

      await tools.getApps();

      let miapass = '';

      if (process.env.PROD !== 1) {
        testmsgwebpush();

        // tools.sendNotifToAdmin('Riparti', 'Riparti');

        if (miapass !== '') {
          let crypt = tools.cryptdata(miapass);
          let decrypt = tools.decryptdata(crypt);

          console.log('crypted:', crypt);
          console.log('decrypted:', decrypt);
        }

        mycron();
      }

      miapass = 'PROVA123@';
      let crypt = tools.cryptdata(miapass);
      let decrypt = tools.decryptdata(crypt);

      telegrambot = require('./telegram/telegrambot');

      if (decrypt === miapass) {
        console.log('✅ Decrypt OK');
        // OK FUNZIONA
      } else {
        let msgerr = '❌ ERRORE! la decrittazione non funziona! ';
        console.error(msgerr);
        await telegrambot.sendMsgTelegramToTheAdminAllSites(msgerr, false);
      }

      await inizia();

      await resetProcessingJob();

      populate.popolaTabelleNuove();

      faitest();

      // ----------------- MAILCHIMP -----
      const querystring = require('querystring');
      const mailchimpClientId = 'xxxxxxxxxxxxxxxx';

      app.get('/mailchimp/auth/authorize', function (req, res) {
        res.redirect(
          'https://login.mailchimp.com/oauth2/authorize?' +
            querystring.stringify({
              response_type: 'code',
              client_id: mailchimpClientId,
              redirect_uri: 'http://127.0.0.1:3000/mailchimp/auth/callback',
            })
        );
      });
    }

    // -----------------

    function populateDBadmin() {
      const cfgserv = [
        {
          _id: new ObjectId(),
          idapp: '9',
          chiave: 'vers',
          userId: 'ALL',
          valore: '0.1.2',
        },
      ];

      let cfg = new CfgServer(cfgserv[0]).save();
    }

    async function mycron() {
      try {
        const sendemail = require('./sendemail');

        const { Cron } = require('./models/cron');

        const arr = await tools.getApps();
        for (const app of arr) {
          await sendemail.checkifPendingNewsletter(app.idapp);
          await sendemail.checkifSentNewsletter(app.idapp);

          await Cron.startJobCron(app.idapp);
        }
      } catch (e) {
        console.error('Err mycron', e);
      }
    }

    async function mycron_30min() {
      for (const app of await tools.getApps()) {
        let enablecrontab = false;

        enablecrontab = await Settings.getValDbSettings(app.idapp, tools.ENABLE_CRONTAB, false);

        if (enablecrontab) {
          // ...
        }
      }
    }

    async function mycron_everyday() {
      try {
        const { User } = require('./models/user');

        const arrapps = await tools.getApps();
        for (const app of arrapps) {
          // Azzera le richieste di password:
          const usersblocked = await User.find({ idapp: app.idapp, retry_pwd: { $exists: true, $gte: 29 } }).lean();
          for (const user of usersblocked) {
            await User.findOneAndUpdate({ _id: user._id }, { $set: { retry_pwd: 20 } });
            let text = `⚠️⚠️⚠️ L\'utente ${user.username} (${user.name} ${user.surname}) viene sbloccato dal numero massimo di tentativi di richiesta password!\nTelerlo d\'occhio !\n@${user.profile.username_telegram}`;
            await telegrambot.sendMsgTelegramToTheAdminAllSites(text, false);
          }
        }
      } catch (e) {
        console.error('mycron_everyday: ', e);
      }
    }

    function testmsgwebpush() {
      const { User } = require('./models/user');

      // console.log('nomeapp 1: ' , tools.getNomeAppByIdApp(1));
      // console.log('nomeapp 2: ' , tools.getNomeAppByIdApp(2));

      User.find({ username: 'surya1977', idapp: '1' }).then(async (arrusers) => {
        if (arrusers !== null) {
          for (const user of arrusers) {
            await tools
              .sendNotificationToUser(user._id, 'Server', 'Il Server è Ripartito', '/', '', 'server', [])
              .then((ris) => {
                if (ris) {
                } else {
                  // already sent the error on calling sendNotificationToUser
                }
              });
          }
        }
      });
    }

    // Esecuzione ogni 1 minuto (*/1 * * * *)
    // La sintassi di cron è:
    // 0 12 * * *  comando
    // che significa: esegui il comando ogni giorno alle 12:00
    // La sintassi di node-cron è:
    // cron.schedule('0 12 * * *', () => {
    // che significa: esegui il comando ogni giorno alle 12:00
    // La sintassi di node-cron con */1 esegue il comando ogni 1 minuto
    cron.schedule('*/1 * * * *', () => {
      // console.log('Running Cron Job');
      // if (!process.env.VITE_DEBUG) {
      mycron();
      // }
    });

    // Cron every 1 HOUR
    cron.schedule('*/60 * * * *', async () => {
      if (!process.env.VITE_DEBUG) {
        mycron_30min();
      }
    });

    // Cron every 21:00 (1 volta al giorno)
    cron.schedule('0 21 * * *', async () => {
      mycron_everyday();
    });

    // mycron_30min();

    // tools.writelogfile('test', 'prova.txt');

    async function resetProcessingJob() {
      const { Newstosent } = require('./models/newstosent');

      arrrec = await Newstosent.find({});

      for (const rec of arrrec) {
        rec.processing_job = false;
        await Newstosent.findOneAndUpdate({ _id: rec.id }, { $set: rec }, { new: false }).then((item) => {});
      }
    }

    //app.listen(port, () => {
    //  console.log(`Server started at port ${port}`);
    //});

    async function inizia() {
      try {
        if (false) {
          const url = 'https://raw.githubusercontent.com/matteocontrini/comuni-json/master/comuni.json';
          const outputPath = './comuni_italia_geojson.json';
          downloadGeoJSON(url, outputPath);
        }

        mycron_everyday();

        if (process.env.NODE_ENV === 'development') {
          await telegrambot.sendMsgTelegram(
            tools.FREEPLANET,
            shared_consts.ADMIN_USER_SERVER,
            `Ciao ${telegrambot.ADMIN_USER_NAME_SERVER}!`
          );

          await telegrambot.sendMsgTelegramByIdTelegram(
            tools.FREEPLANET,
            telegrambot.ADMIN_IDTELEGRAM_SERVER,
            `Ciao ${telegrambot.ADMIN_USER_NAME_SERVER}\n` + `🔅 Il Server ${process.env.DATABASE} è appena ripartito!`
          );
        } else {
          await telegrambot.sendMsgTelegramToTheAdminAllSites(
            `Ciao Admin\n` + `🔅🔅🔅 Il Server col BOT di {appname} è appena ripartito!`,
            false
          );
        }

        await Site.createFirstUserAdmin();

        /*const {Circuit} = require('./models/circuit');
    
        await Circuit.setDeperimentoOff();
    
         */
      } catch (e) {}
    }

    //

    // telegrambot.sendMsgTelegramToTheManagers('7', 'PROVAAA!');

    // if (process.env.PROD !== 1) {
    //   const reg = require('./reg/registration');
    //   const link = reg.getlinkregByEmail('7', 'tomasihelen@dasdasgmail.comAAAA' , 'HelenTomasidasdasd');
    //   const link2 = reg.getlinkregByEmail('7', 'tomasihelen@gmail.com' , 'HelenTomasi');
    //   //const link2 = reg.getlinkregByEmail('7', 'elenaliubicich@gmail.com' , 'Elenaliu');
    //
    //   console.log(link);
    //   console.log(link2);
    // }

    async function estraiImmagini(table) {
      const { User } = require('./models/user');

      let idapp = '13';

      let arrlist;

      const globalTables = require('./tools/globalTables');

      const mytable = globalTables.getTableByTableName(table);
      if (!mytable) return;

      console.log('INIZIO - estraiImmagini', table);

      arrlist = await mytable.find({ idapp }).lean();

      let file = '';
      let filetocheck = '';
      let dirmain = '';
      let filefrom = '';
      let filefrom2 = '';

      try {
        if (!tools.sulServer()) {
          dirmain = server_constants.DIR_PUBLIC_LOCALE;
        }

        let dir = tools.getdirByIdApp(idapp) + dirmain + '/upload/';

        for (const rec of arrlist) {
          const myuser = await User.findOne({ idapp, _id: rec.userId }).lean();
          if (myuser) {
            const myphotos = rec.photos;

            if (myphotos.length > 0) {
              let folderprof = dir + 'profile/' + myuser.username;

              try {
                // console.log('checkdir', folderprof);
                if (!(await tools.isFileExistsAsync(folderprof))) {
                  console.log('*** Creadir', folderprof);
                  await fs.mkdirSync(folderprof);
                }

                folderprof = dir + 'profile/' + myuser.username + '/' + table;
                // console.log('checkdir', folderprof);
                if (!(await tools.isFileExistsAsync(folderprof))) {
                  console.log('creadir', folderprof);
                  await fs.mkdirSync(folderprof);
                }
              } catch (e) {}
            }

            for (const photo of myphotos) {
              if (photo.imagefile) {
                file = dir + 'profile/' + myuser.username + '/' + table + '/' + photo.imagefile;
                filefrom = dir + 'profile/undefined/' + table + '/' + photo.imagefile;
                filefrom2 = dir + 'profile/' + myuser.username + '/' + photo.imagefile;

                // console.log('file', file);
                // console.log('filefrom', filefrom);

                if (!(await tools.isFileExistsAsync(file))) {
                  // non esiste
                  console.log('non esiste', file);
                  console.log('   filefrom', filefrom);
                  console.log('   filefrom2', filefrom2);
                }

                if (!(await tools.isFileExistsAsync(file)) && (await tools.isFileExistsAsync(filefrom))) {
                  console.log('@@@@@@  copia file:', filefrom, 'a', file);
                  tools.copy(filefrom, file);
                }
                if (!(await tools.isFileExistsAsync(file)) && (await tools.isFileExistsAsync(filefrom2))) {
                  console.log('@@@@@@  copia file 2:', filefrom2, 'a', file);
                  tools.copy(filefrom2, file);
                }
              }
            }
          }
        }
        console.log('FINE - estraiImmagini', table);
      } catch (e) {
        console.error('e', e);
      }
    }

    async function estraiTutteLeImmagini() {
      await estraiImmagini('myskills');
      await estraiImmagini('mygoods');
      await estraiImmagini('mybachecas');
    }

    async function faitest() {
      // console.log('Fai Test:')

      const testfind = false;

      // const $vers = tools.getVersionint('1.92.45');

      if (true) {
        // tools.execScript("ls -la");
      }

      if (false) {
        prova = tools.removeAtChar('@prova');
      }

      if (false) {
        const prova = tools.getConfSiteOptionEnabledByIdApp('13', shared_consts.ConfSite.Notif_Reg_Push_Admin);
        console.log('prova', prova);
      }

      if (testfind) {
        const { City } = require('./models/city');

        let miacity = 'roma';
        const ris = await City.findByCity(miacity);

        console.log('ris', ris);
      }

      const { User } = require('./models/user');

      if (false) {
        let myuser = await User.findOne({
          idapp: '1',
          username: 'paoloar77',
        });
        const langdest = 'it';

        telegrambot.askConfirmationUser(myuser.idapp, shared_consts.CallFunz.REGISTRATION, myuser);
      }

      const inviaemailtestsurya = false

      if (inviaemailtestsurya) {
        const user = await User.findOne({
          idapp: 13,
          username: 'surya2',
        });

        const sendemail = require('./sendemail');
        

        await sendemail.sendEmail_Registration('it', 'paolo@arcodiluce.it', user, '13', '');
      }

      if (false) {
        const { User } = require('./models/user');

        const idapp = tools.FREEPLANET;
        const idreg = 0;

        try {
          const user = await User.findOne({
            idapp,
            username: 'paoloar773',
          });

          user.aportador_solidario = 'surya1977';

          let mylocalsconf = {
            idapp,
            dataemail: null,
            locale: user.lang,
            nomeapp: tools.getNomeAppByIdApp(idapp),
            strlinksito: tools.getHostByIdApp(idapp),
            strlinkreg: '',
            username: user.username,
            name: user.name,
            surname: user.surname,
            forgetpwd: tools.getHostByIdApp(idapp) + '/requestresetpwd',
            emailto: '',
            user,
          };

          await telegrambot.notifyToTelegram(telegrambot.phase.REGISTRATION, mylocalsconf);
        } catch (e) {
          console.log('error ' + e);
        }
      }
    }

    // Funzione migliorata per ottenere chiave e certificato
    async function getCredentials(hostname) {
      try {
        let keyPath, certPath;

        if (NUOVO_METODO_TEST) {
          if (METODO_MULTI_CORS) {
            // Percorso basato su hostname (Let's Encrypt)
            keyPath = `/etc/letsencrypt/live/${hostname}/${process.env.PATH_CERT_KEY}`;
            certPath = `/etc/letsencrypt/live/${hostname}/${process.env.PATH_SERVER_CRT}`;
          } else {
            // Percorso relativo
            keyPath = path.resolve(`./${process.env.PATH_CERT_KEY}`);
            certPath = path.resolve(`./${process.env.PATH_SERVER_CRT}`);
          }

          // Verifica esistenza file
          if (!(await tools.isFileExistsAsync(keyPath))) {
            throw new Error(`Chiave privata non trovata: ${keyPath}`);
          }
          if (!(await tools.isFileExistsAsync(certPath))) {
            throw new Error(`Certificato non trovato: ${certPath}`);
          }

          // Leggi chiave e certificato
          const key = fs.readFileSync(keyPath, 'utf8');
          const cert = fs.readFileSync(certPath, 'utf8');

          // Restituisci oggetto con credenziali + configurazione TLS avanzata
          return {
            key,
            cert,
            ciphers:
              'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384',
            honorCipherOrder: true,
            secureOptions: require('constants').OPENSSL_OPTIONS_TLS_NODELAY,
            secureProtocol: 'TLSv1_2_method', // Forza TLS 1.2+ (meglio se usi TLSv1_3)
          };
        } else {
          // Metodo legacy (opzionale)
          throw new Error('Metodo legacy non supportato');
        }
      } catch (error) {
        console.error(`[getCredentials] Errore per ${hostname}:`, error.message);
        throw error;
      }
    }
    // 🔧 Funzione factory per creare e configurare un server HTTPS
    function createHttpsServer({ hostname, port, website, app, credentials, timeoutMinutes = 5 }) {
      const server = https.createServer(credentials, app);

      const timeoutMs = 1000 * 60 * timeoutMinutes;

      // ⏱️ Timeout globale per la connessione TCP
      server.setTimeout(timeoutMs, () => {
        console.log(`TCP timeout su server: ${hostname}:${port} ${website}`);
      });

      // ⏱️ Timeout per singola richiesta HTTP
      server.on('request', (req, res) => {
        req.setTimeout(timeoutMs);
        res.setTimeout(timeoutMs);
      });

      // 📡 Eventuali altri eventi utili
      server.on('clientError', (err, socket) => {
        console.error(`Client error su ${hostname}:${port}:`, err.message);
      });

      // Avvia il server
      server.listen(port, () => {
        console.log(
          '⭐️⭐️⭐️⭐️⭐️ HTTPS server: %s Port: %d%s',
          hostname,
          port,
          website ? ' WebSite = ' + website : ''
        );
      });

      return server;
    }

    function parseDomains() {
      let domains = [];
      let domainsAllowed = [];
      try {
        if (process.env.DOMAINS) domains = JSON.parse(process.env.DOMAINS);
        if (process.env.DOMAINS_ALLOWED) domainsAllowed = JSON.parse(process.env.DOMAINS_ALLOWED);
      } catch (error) {
        console.error('Errore parsing DOMAINS:', error);
      }
      return { domains, domainsAllowed };
    }

    function buildAllowedOrigins(domains, domainsAllowed, isProduction) {
      if (!isProduction) {
        return [
          'https://localhost:3000',
          'https://localhost:8089',
          'https://localhost:8082',
          'https://localhost:8083',
          'https://localhost:8084',
          'https://localhost:8085',
          'https://localhost:8088',
          'https://localhost:8099',
          'https://localhost:8094',
          'https://192.168.8.182',
          'https://192.168.8.182:8084/',
          'http://192.168.8.182:8084/',
        ];
      }

      const baseOrigins = domains.flatMap((domain) => [
        `https://${domain.hostname}`,
        `https://api.${domain.hostname}`,
        `https://test.${domain.hostname}`,
        `https://testapi.${domain.hostname}`,
        `http://${domain.hostname}`,
        `http://api.${domain.hostname}`,
        `http://test.${domain.hostname}`,
        `http://testapi.${domain.hostname}`,
      ]);

      console.log('baseOrigins:', baseOrigins.map(origin => `'${origin}'`).join(', '));

      const allowedExtra = domainsAllowed.flatMap((domain) => [`https://${domain}`, `http://${domain}`]);

      return [...baseOrigins, ...allowedExtra];
    }

    function createCorsOptions(domains, domainsAllowed, isProduction, noCors = false) {
      if (noCors) {
        console.log('NOCORS mode enabled');
        return {
          exposedHeaders: ['x-auth', 'x-refrtok'],
        };
      }

      const allowedOrigins = buildAllowedOrigins(domains, domainsAllowed, isProduction);

      let originValidator = (origin, callback) => {
        if (!origin) {
          // console.log('✅ Origin undefined or empty — allowing');
          return callback(null, true);
        }

        if (typeof origin !== 'string' || !/^https?:\/\/[^\s/$.?#].[^\s]*$/.test(origin)) {
          console.error('❌ Invalid origin:', origin);
          return callback(new Error('Origine non valida'), false);
        }

        if (allowedOrigins.includes(origin)) {
          return callback(null, true);
        }

        console.warn('❌ Origin blocked:', origin);
        return callback(new Error('CORS non permesso per questa origine'), false);
      };

      if (app.get('env') === 'development') {
        originValidator = (_origin, callback) => callback(null, true);
      }

      return {
        origin: originValidator,
        credentials: true,
        methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
        allowedHeaders: [
          'Origin',
          'X-Requested-With',
          'Content-Type',
          'Accept',
          'Authorization',
          'x-auth',
          'x-refrtok',
        ],
        exposedHeaders: ['x-auth', 'x-refrtok'],
        maxAge: 86400,
        preflightContinue: false,
        optionsSuccessStatus: 204,
      };
    }

    function setupMiddleware(app, corsOptions, isDebug = false) {
      app.use(helmet());
      app.use(cors(corsOptions));
      app.set('trust proxy', true);
      app.use(express.json());
      
      app.use(morgan('dev'));
      app.use(rateLimit);

      app.get('/health', (_req, res) => res.json({ ok: true }));

      app.use('/apinew', apiRouter);

      // app.use(notFound);
      app.use(errorHandler);

      app.options('*', cors(corsOptions));

      if (isDebug) {
        app.use((req, res, next) => {
          console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
          console.log('Request Headers:', req.headers);

          const oldSend = res.send;
          res.send = function (...args) {
            console.log('Response Headers:', res.getHeaders());
            return oldSend.apply(res, args);
          };

          next();
        });
      }

      app.use((err, req, res, next) => {
        if (err.message === 'CORS non permesso per questa origine') {
          console.error('❌ Errore CORS:', {
            origin: req.headers.origin,
            method: req.method,
            path: req.path,
          });
          return res.status(403).json({
            error: `❌ CORS non permesso per questa origine (${req.headers.origin})`,
            origin: req.headers.origin,
          });
        }
        next(err);
      });
    }

    async function createHttpOrHttpsServer(app, port, isProduction, domains) {
      if (isProduction) {
        const promises = domains.map(async (domain) => {
          const credentials = await getCredentials(domain.hostname);
          return createHttpsServer({
            hostname: domain.hostname,
            port: domain.port,
            website: domain.website,
            app,
            credentials,
            timeoutMinutes: 6,
          });
        });
        await Promise.all(promises);
        return null;
      }

      if (process.env.HTTPS_LOCALHOST === 'true') {
        try {
          const key = fs.readFileSync(path.resolve(`./${process.env.PATH_CERT_KEY}`), 'utf8');
          const cert = fs.readFileSync(path.resolve(`./${process.env.PATH_SERVER_CRT}`), 'utf8');

          const credentials = {
            key,
            cert,
            ciphers:
              'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384',
            honorCipherOrder: true,
            secureProtocol: 'TLSv1_2_method',
          };

          const httpsServer = https.createServer(credentials, app);
          httpsServer.listen(port, '0.0.0.0');
          console.log('⭐️ HTTPS server running locally on port', port);
          return httpsServer;
        } catch (error) {
          console.error('Errore caricamento certificati HTTPS locali:', error.message);
          // fallback HTTP server
        }
      }

      const httpServer = http.createServer(app);
      httpServer.listen(port);
      console.log('⭐️ HTTP server running on port', port);
      return httpServer;
    }

    function setupWebSocketServer(httpOrHttpsServer) {
      if (!httpOrHttpsServer) {
        console.error('Nessun server HTTP o HTTPS disponibile per WebSocket');
        return null;
      }

      const wss = new WebSocket.Server({ server: httpOrHttpsServer });

      wss.on('connection', (ws) => {
        console.log('Client socket connected...');

        const { User } = require('./models/user');
        const pty = require('node-pty');
        let scriptProcess = null;

        ws.on('message', async (message) => {
          try {
            const parsed = JSON.parse(message);

            if (parsed.type === 'start_script' && User.isAdminById(parsed.user_id)) {
              if (scriptProcess) scriptProcess.kill();

              const scriptPath = path.join(__dirname, '..', '..', parsed.scriptName);
              if (!(await tools.isFileExistsAsync(scriptPath))) {
                return ws.send(JSON.stringify({ type: 'error', data: 'Script non trovato o non autorizzato' }));
              }

              scriptProcess = pty.spawn('bash', [scriptPath], {
                name: 'xterm-color',
                cols: 80,
                rows: 40,
                cwd: process.cwd(),
                env: process.env,
              });

              let buffer = '';
              scriptProcess.on('data', (data) => {
                buffer += data;
                ws.send(JSON.stringify({ type: 'output', data }));

                if (
                  buffer.endsWith(': ') ||
                  buffer.includes('? ') ||
                  buffer.toLowerCase().includes('password') ||
                  buffer.includes('Inserisci') ||
                  buffer.includes('Inserted') ||
                  buffer.includes('(Y)')
                ) {
                  ws.send(JSON.stringify({ type: 'input_required', prompt: data.trim() }));
                  buffer = '';
                }

                if (buffer.length > 5024) buffer = buffer.slice(-500);
              });

              scriptProcess.on('exit', (code) => {
                const closeMsg = code === 0 ? '*** FINE SCRIPT ***' : `Script terminato con codice ${code}`;
                ws.send(JSON.stringify({ type: 'close', data: closeMsg }));
              });
            } else if (parsed.type === 'input') {
              if (scriptProcess) {
                scriptProcess.write(parsed.data + '\n');
              }
            }
          } catch (err) {
            console.error("Errore durante l'elaborazione del messaggio:", err.message);
          }
        });

        ws.on('close', () => {
          console.log('*** Client socket disconnected');
          if (scriptProcess) scriptProcess.kill();
        });
      });

      return wss;
    }

    async function startServer(app, port) {
      try {
        const isProduction = ['production', 'test'].includes(process.env.NODE_ENV);
        const ISDEBUG = false;
        const NOCORS = false;

        const { domains, domainsAllowed } = parseDomains();
        

        
        console.log('domains:', domains);
        console.log('isProduction:', isProduction);

        const corsOptions = createCorsOptions(domains, domainsAllowed, isProduction, NOCORS);

        setupMiddleware(app, corsOptions, ISDEBUG);

        const server = await createHttpOrHttpsServer(app, port, isProduction, domains);

        const wss = setupWebSocketServer(server);

        return { server, wss };
      } catch (error) {
        console.error('Errore in startServer:', error);
      }
    }
  })
  .catch((err) => {
    console.error('Impossibile connettersi al database dopo diversi tentativi:', err);
    process.exit(1); // Termina il processo se non riesce a connettersi
  });

function add_numbers(a, b) {}

module.exports = { app };
