const axios = require('axios');

const mongoose = require('mongoose').set('debug', false)
const Schema = mongoose.Schema;

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

mongoose.Promise = global.Promise;
mongoose.level = "F";


class MssqlMigrator {
    /**
     * Costruttore della classe MssqlMigrator
     * @param {string} serverUrl - URL del server che esegue le query MSSQL
     * @param {string} apiKey - API Key per l'autenticazione
     */
    constructor() {
        this.serverUrl = process.env.SERVER_A_URL;
        this.apiKey = process.env.API_KEY_MSSQL;
    }

    /**
     * Migra una lista di tabelle MSSQL in MongoDB usando Mongoose
     * @param {string[]} tableNames - Lista dei nomi delle tabelle MSSQL
     * @returns {string} logs - Lista dei log di esecuzione
     */
    async migrateTables(tableNames) {

        try {

            const numtables = tableNames.length;
            let indtab = 0;
            let indtabok = 0;
            const logs = [];
            for (const rectable of tableNames) {
                try {
                    const tableName = rectable.table;
                    const usaDataOra = rectable.usaDataOra;
                    const fieldId = rectable.fieldId;

                    const percentuale = ((indtab / numtables) * 100).toFixed(2);
                    logs.push(`\n>> Recupero dati da MSSQL per la tabella: ${tableName} - (Completamento: ${percentuale}%)`);
                    console.log(logs[logs.length - 1]);
                    let dataQuery = `SELECT * FROM ${tableName}`;

                    if (usaDataOra) {
                        dataQuery = `SELECT T.* FROM ${tableName} T`;
                        dataQuery += ` JOIN (
                            SELECT ${fieldId}, MAX(DataOra) AS data
                            FROM ${tableName}
                            GROUP BY ${fieldId}
                        ) b ON T.${fieldId} = b.${fieldId} AND T.DataOra = b.data; `;
                    }

                    console.log('query', dataQuery);

                    let dataResponse = null;

                    try {
                        dataResponse = await axios.post(
                            `${this.serverUrl}/query`,
                            { query: dataQuery },
                            { headers: { 'x-api-key': this.apiKey } },
                            null,
                            { timeout: 900000 });
                    } catch (error) {
                        console.error('Error: ', error.response?.data?.error || error.message || error);
                        if (error.message === 'socket hang up') {
                            console.log('Error: hangup, waiting 5 seconds and retrying...');
                            await new Promise(resolve => setTimeout(resolve, 5000));


                            dataResponse = await axios.post(
                                `${this.serverUrl}/query`,
                                { query: dataQuery },
                                { headers: { 'x-api-key': this.apiKey } },
                                null,
                                { timeout: 900000 });

                        } else {
                            console.error('Unexpected error while fetching data from MSSQL:', error.message);
                            // throw error;
                        }
                    }


                    const records = dataResponse?.data;

                    if (!records || records.length === 0) {
                        logs.push(`⚠️ Nessun record trovato per la tabella: ${tableName}`);
                        console.log(logs[logs.length - 1]);
                        continue;
                    }

                    const sample = records[0];
                    const schemaDef = {};

                    for (const key of Object.keys(sample)) {
                        const value = sample[key];
                        if (typeof value === 'string' && key.startsWith('Data') && !isNaN(Date.parse(value))) {
                            schemaDef[key] = Date;
                        } else if (typeof value === 'number') {
                            schemaDef[key] = Number;
                        } else if (typeof value === 'boolean') {
                            schemaDef[key] = Boolean;
                        } else if (value instanceof Date) {
                            schemaDef[key] = Date;
                        } else {
                            schemaDef[key] = mongoose.Schema.Types.Mixed;
                        }
                    }

                    const dynamicSchema = new mongoose.Schema(schemaDef, { strict: false });
                    const modelName = tableName.charAt(0).toUpperCase() + tableName.slice(1);

                    // Se il modello esiste già, lo riutilizziamo
                    const DynamicModel = mongoose.models[modelName] || mongoose.model(modelName, dynamicSchema);

                    // ❗ Elimina tutti i documenti esistenti prima dell'inserimento
                    await DynamicModel.deleteMany({});

                    logs.push(`✅ Inserimento di ${records.length} record nella collezione MongoDB: ${modelName}`);
                    console.log(logs[logs.length - 1]);
                    await DynamicModel.insertMany(records);

                    indtabok++;
                } catch (error) {
                    logs.push(`❌ Errore con la tabella ${tableName}:`, error.message);
                    console.log(logs[logs.length - 1]);
                }

                indtab++;

                
            }

            logs.push(`\n🎉 ${indtabok} tabelle su ${numtables} sono state migrate.`);
            console.log(logs[logs.length - 1]);
            return logs.join('\n');
        } catch (error) {
            logs.push(`❌ Errore migrateTables:`, error.message);
            console.log(logs[logs.length - 1]);
        }
    }
}


module.exports = MssqlMigrator;