/**
 * fedapay-init-transaction
 *
 * Initialise un paiement FedaPay pour un abonnement et renvoie l'URL de paiement
 * Implémentation via SDK FedaPay si disponible, sinon fallback axios.
 * Réf doc: https://docs.fedapay.com/integration-api/fr/librairies-fr
 */

module.exports = {
    friendlyName: 'Init FedaPay transaction',

    inputs: {
        abonnement: { type: 'ref', required: true },
        utilisateur: { type: 'ref', required: true },
        offre: { type: 'ref', required: true },
        returnUrl: { type: 'string' },
        callbackUrl: { type: 'string' }
    },

    exits: {
        success: { description: 'Transaction initialisée' },
        error: { description: 'Erreur lors de l’init FedaPay' }
    },

    fn: async function ({ abonnement, utilisateur, offre, returnUrl, callbackUrl }, exits) {
        try {
            const cfg = sails.config.externalApis.fedapay || {};
            const env = (cfg.env || 'sandbox').toLowerCase() === 'live' ? 'live' : 'sandbox';
            const apiKey = cfg.apiKey;
            if (!apiKey) { throw new Error('FEDAPAY_API_KEY manquant'); }

            // Normalisation URLs: FedaPay exige des URLs HTTPS publiques
            const isHttp = (u) => typeof u === 'string' && /^https?:\/\//i.test(u);
            const cbUrl = isHttp(callbackUrl) ? callbackUrl : (isHttp(cfg.callbackUrl) ? cfg.callbackUrl : undefined);
            // Injecter codeAbonnement dans l’URL de retour afin de relayer vers l’app
            const baseReturn = isHttp(returnUrl) ? returnUrl : (isHttp(cfg.returnUrl) ? cfg.returnUrl : undefined);
            const retUrl = baseReturn ? `${baseReturn}${baseReturn.includes('?') ? '&' : '?'}codeAbonnement=${encodeURIComponent(abonnement.codeAbonnement)}` : undefined;

            // Normalisation du téléphone en objet { number, country }
            const mapIndicatifToCountry = (indicatif) => {
                const map = { '229': 'BJ', '225': 'CI', '228': 'TG', '221': 'SN', '223': 'ML', '226': 'BF', '224': 'GN', '227': 'NE', '237': 'CM' };
                return map[indicatif || ''] || undefined;
            };
            const numberRaw = (utilisateur.telephone1 || '').trim();
            const indicatifDigits = (utilisateur.indicatif1 || '').toString().replace(/\D/g, '');
            let cleaned = numberRaw.replace(/\s+/g, '');
            if (cleaned.startsWith('00')) {
                cleaned = `+${cleaned.slice(2)}`;
            } else if (cleaned.startsWith('+')) {
                // ok
            } else if (indicatifDigits && cleaned.startsWith(indicatifDigits)) {
                cleaned = `+${cleaned}`;
            } else if (indicatifDigits) {
                cleaned = `+${indicatifDigits}${cleaned}`;
            }
            const e164Regex = /^\+[1-9]\d{6,14}$/;
            const country = mapIndicatifToCountry(indicatifDigits);
            const phoneObject = country && e164Regex.test(cleaned)
                ? { number: cleaned, country: country.toLowerCase() }
                : undefined;
            sails.log.info('FedaPay phone candidate', { raw: numberRaw, indicatifDigits, cleaned, valid: e164Regex.test(cleaned), country: country ? country.toLowerCase() : null });

            // Forcer devise et montant conformes
            const rawCurrency = (abonnement.devise || offre.devise || 'XOF');
            const currency = (typeof rawCurrency === 'string' && /^[A-Za-z]{3}$/.test(rawCurrency)) ? rawCurrency.toUpperCase() : 'XOF';
            const amount = Number.isFinite(+abonnement.montantFinal) ? Math.round(+abonnement.montantFinal) : 0;
            if (!amount || amount < 1) { throw new Error('Montant invalide pour FedaPay'); }
            if (!currency || typeof currency !== 'string' || currency.length !== 3) { throw new Error('Devise invalide/absente pour FedaPay'); }

            const firstName = (utilisateur.prenom || utilisateur.nom || 'Client').toString();
            const lastName = (utilisateur.nom || '').toString();
            const email = utilisateur.email || undefined;

            // Validation et fallback pour le nom de l'offre
            const offreNom = offre?.nom || offre?.codeOffre || 'Standard';
            if (!offre?.nom) {
                sails.log.warn('Nom de l\'offre manquant, utilisation du code comme fallback:', {
                    codeOffre: offre?.codeOffre,
                    offre: offre
                });
            }

            const metadata = {
                codeAbonnement: abonnement.codeAbonnement,
                codeParent: abonnement.codeParent,
                codeEcole: abonnement.codeEcole,
                codeOffre: abonnement.codeOffre,
                reference: `FDY_${abonnement.codeAbonnement}`
            };

            sails.log.info('FedaPay init params', {
                amount,
                currency,
                cbUrl,
                retUrl,
                deviseAbonnement: abonnement.devise || null,
                deviseOffre: offre.devise || null,
                codeAbonnement: abonnement.codeAbonnement,
                codeOffre: abonnement.codeOffre,
                offreNom: offreNom,
                offreNomOriginal: offre.nom,
                metadata
            });

            // Tenter SDK FedaPay si dispo et compatible
            let FedaPay = null;
            try { FedaPay = require('fedapay'); } catch (e) { FedaPay = null; }
            if (FedaPay && FedaPay.Transaction && (typeof FedaPay.setApiKey === 'function' || typeof FedaPay.init === 'function')) {
                try {
                    if (typeof FedaPay.setApiKey === 'function' && typeof FedaPay.setEnvironment === 'function') {
                        FedaPay.setApiKey(apiKey);
                        FedaPay.setEnvironment(env);
                    } else if (typeof FedaPay.init === 'function') {
                        FedaPay.init({ api_key: apiKey, environment: env });
                    }

                    // Créer client (customer)
                    let customer = null;
                    try {
                        if (FedaPay.Customer && typeof FedaPay.Customer.create === 'function') {
                            customer = await FedaPay.Customer.create({ firstname: firstName, lastname: lastName || 'Client', email: email, phone_number: phoneObject });
                        }
                    } catch (e) {
                        if (FedaPay.Customer && typeof FedaPay.Customer.create === 'function') {
                            customer = await FedaPay.Customer.create({ firstname: firstName, lastname: lastName || 'Client', email: email });
                        }
                    }

                    const sdkPayload = {
                        amount,
                        currency: { iso: currency },
                        description: `Abonnement ${offreNom} (${abonnement.codeAbonnement})`,
                        callback_url: cbUrl,
                        return_url: retUrl,
                        merchant_reference: metadata.reference,
                        custom_metadata: metadata,
                        customer: customer?.id
                    };
                    sails.log.info('FedaPay SDK payload', sdkPayload);
                    const trx = await FedaPay.Transaction.create(sdkPayload);

                    const paymentUrl = trx?.url || trx?.payment_url || trx?.redirect_url || null;
                    const fedapayTransactionId = trx?.id;
                    if (!paymentUrl) { throw new Error('URL de paiement introuvable (SDK)'); }

                    sails.log.info('FedaPay SDK utilisé pour init transaction');
                    return exits.success({ paymentUrl, fedapayTransactionId, reference: metadata.reference });
                } catch (sdkErr) {
                    sails.log.warn('SDK FedaPay indisponible/incompatible, fallback REST:', sdkErr.message);
                }
            }

            // Fallback REST (axios)
            const axios = require('axios');
            const base = env === 'live' ? 'https://api.fedapay.com/v1' : 'https://sandbox-api.fedapay.com/v1';
            const headers = { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' };

            // Payload top-level, conforme à la doc cURL
            const payload = {
                description: `Abonnement ${offreNom} (${abonnement.codeAbonnement})`,
                amount: amount,
                currency: { iso: currency },
                callback_url: cbUrl,
                return_url: retUrl,
                merchant_reference: metadata.reference,
                custom_metadata: metadata,
                customer: { firstname: firstName, lastname: lastName || 'Client', email: email, phone_number: phoneObject }
            };

            const safeHeaders = { ...headers, Authorization: 'Bearer ***' };
            sails.log.info('FedaPay REST payload', { base, headers: safeHeaders, payload });

            const resp = await axios.post(`${base}/transactions`, payload, { headers });
            const data = resp.data || {};
            sails.log.info('FedaPay REST create response', data);
            const trxObj = data?.transaction || data?.['v1/transaction'] || data;
            let paymentUrl = trxObj?.payment_url || trxObj?.url || data?.url || data?.payment_url;
            let fedapayTransactionId = trxObj?.id || data?.id;

            // Note: pas de récupération par référence marchand (merchant_reference non supporté)

            // Si pas d’URL directe, générer un token
            if (!paymentUrl && fedapayTransactionId) {
                try {
                    const tokenResp = await axios.post(`${base}/transactions/${fedapayTransactionId}/token`, {}, { headers });
                    const tokenData = tokenResp.data || {};
                    const tokenTrx = tokenData?.transaction || tokenData?.['v1/transaction'] || tokenData;
                    paymentUrl = tokenTrx?.payment_url || tokenTrx?.url || tokenData?.url || tokenData?.payment_url;
                    sails.log.info('FedaPay REST token payload', { transactionId: fedapayTransactionId, tokenData });
                } catch (tokenErr) {
                    sails.log.warn('Echec génération token FedaPay REST:', tokenErr.response?.data || tokenErr.message);
                }
            }
            if (!paymentUrl) { throw new Error('URL de paiement introuvable (REST)'); }

            sails.log.info('FedaPay REST utilisé pour init transaction');
            return exits.success({ paymentUrl, fedapayTransactionId, reference: metadata.reference });
        } catch (e) {
            const detail = e.response?.data || e.message || e;
            sails.log.error('FedaPay init error:', detail);
            const errMsg = typeof detail === 'string' ? detail : JSON.stringify(detail);
            return exits.error(new Error(errMsg));
        }
    }
}; 