const db = require("../models");
const model = db.transaccion;
const Op = db.Sequelize.Op;

const { isInteger, postData, randomText, generatePDF, formatNumber } = require('../helpers/util');
const { FirmarPdfExtended } = require('../helpers/firma');

const ambiente = require('../config/ambiente.config');

const path = require('path');
const fs = require('fs');
const ejs = require('ejs');
const dayjs = require('dayjs');


exports.get = async (req, res) => {
    try {
        const id = req.params.id;
        var condition = id ? { id_transaccion: id } : null;

        const data = await model.findAll({ where: condition, order: [['id_transaccion', 'ASC']], });
        return res.status(200).send(data);
    }
    catch (err) {
        return res.status(500).send({ error: "error: " + err.message })
    }
}


exports.getContrato = async (req, res) => {
    try {

        let id = req.params.id?.trim() ?? "";
        if (id == "") return res.status(400).send({ error: "input id" });


        let data = await model.findAll({
            where: { id_contrato: id },
            include: [{
                model: db.estatus,
            }],
        });

        if (!data) return res.status(404).send({ error: "It doesn't exist record with id: " + id });

        data = data.map(item => {
            return {
                id_transaccion: item.id_transaccion,
                createdAt: item.createdAt,
                id_estatus: item.estatus.id_estatus,
                estatus: item.estatus.nombre,
            };
        });

        return res.status(200).send(data);
    }
    catch (err) {
        return res.status(500).send({ error: "error: " + err.message })
    }
}



exports.post = async (req, res) => {

    const t = await db.sequelize.transaction();

    try {

        let id_contrato = req.body.id_contrato || 0;
        let id_estatus = req.body.id_estatus || 0;

        if (id_contrato == 0) return res.status(400).send({ error: "ingrese id_contrato" });
        if (id_estatus == 0) return res.status(400).send({ error: "ingrese id_estatus" });
        if (!isInteger(id_contrato)) return res.status(400).send({ error: "ingrese valor entero en id_contrato" });
        if (!isInteger(id_estatus)) return res.status(400).send({ error: "ingrese valor entero en id_estatus" });

        let contrato = await db.contrato.findOne({ where: { id_contrato: id_contrato } });
        if (!contrato) return res.status(404).send({ error: "no existe contrato con id: " + id_contrato });
        console.log(contrato)

        let estatus = await db.estatus.findOne({ where: { id_estatus: id_estatus } });
        if (!estatus) return res.status(404).send({ error: "no existe estatus con id: " + id_estatus });
        console.log(estatus)

        let condition = { id_contrato: id_contrato, id_estatus: id_estatus };
        let registros = await model.count({ where: condition })

        if (registros > 0) return res.status(400).send({ error: "ya existe registro con esos datos" });

        await model.create({
            id_contrato: id_contrato,
            id_estatus: id_estatus
        }, { transaction: t });

        let message = await GetEmailMessage(estatus.id_estatus, estatus.nombre, contrato.codigo);
        let data = { token: "abc123", subject: "Notification", to: contrato.email, text: message }
        let result = await postData("https://mailer.code-makers.com/mail", data);

        if (result.error != "") return res.status(400).send({ error: "Error to send email: " + result.error });

        await t.commit();

        return res.status(200).send({ mensaje: "Registro almacenado exitosamente" });
    }
    catch (err) {
        await t.rollback();
        return res.status(500).send({ error: "error: " + err.message })
    }
};


exports.put = async (req, res) => {
    try {

        let id_contrato = req.body.id_contrato?.trim() ?? "";
        let id_estatus = req.body.id_estatus?.trim() ?? "";

        if (!req.params.id) return res.status(400).send({ error: "ingrese id" });
        if (id_contrato) return res.status(400).send({ error: "ingrese id_contrato" });
        if (id_estatus) return res.status(400).send({ error: "ingrese id_estatus" });
        if (!isInteger(id_contrato)) return res.status(400).send({ error: "ingrese valor entero en id_contrato" });
        if (!isInteger(id_estatus)) return res.status(400).send({ error: "ingrese valor entero en id_estatus" });

        var id = req.params.id;
        var condition = { id_contrato: id_contrato, id_estatus: id_estatus, id_transaccion: { [Op.not]: id } };

        var registros = await model.count({ where: { id_transaccion: id } });
        if (registros == 0) return res.status(404).send({ error: "No existe registro con el id: " + id });

        registros = await model.count({ where: condition });
        if (registros > 0) return res.status(400).send({ error: "ya existe registro con esos datos" });

        await model.update(
            {
                id_contrato: id_contrato,
                id_estatus: id_estatus
            },
            {
                where: { id_transaccion: id }
            }
        );

        return res.status(200).send({ mensaje: "Registro actualizado exitosamente" });
    }
    catch (err) {
        return res.status(500).send({ error: "error: " + err.message })
    }
};


exports.delete = async (req, res) => {
    try {
        if (!req.params.id) return res.status(400).send({ error: "ingrese id" });

        let id = req.params.id;

        var registros = await model.count({ where: { id_transaccion: id } });

        if (registros == 0) return res.status(404).send({ error: "No existe registro con el id: " + id });

        await model.destroy({
            where: { id_transaccion: id }
        });

        return res.status(200).send({ mensaje: "Registro elimiando exitosamente" });
    }
    catch (err) {
        return res.status(500).send({ error: "error: " + err.message })
    }
};



exports.verify = async (req, res) => {
    try {

        //const filePath = path.join(__dirname, '../public/templates/contract.html');
        const filePath = path.join(__dirname, '../public/templates/template.pdf');

        if (!fs.existsSync(filePath)) return res.send({ error: "It doesn't exist file in path: " + filePath })

        const data = await fs.readFileSync(filePath);
        const base64 = data.toString('base64');
        return res.status(200).send({ mensaje: "Archivo enviado", base64: base64 });

        //var html = await ejs.renderFile(filePath, {}, { async: true });
        //let pdfResult = await generatePDF(html);
        //if (pdfResult.error) return res.status(200).send({ error: pdfResult.error });

        //return res.status(200).send({ mensaje: "Archivo enviado", base64: pdfResult.base64 });

        //const data = await fs.readFileSync(filePath);
        //const base64 = data.toString('base64');

        //return res.status(200).send({ mensaje: "Archivo enviado", base64: base64 });


        //console.log(data);
        //return res.status(200).send({ mensaje: "archivo enviado", bytes: data });

        // // Configura el encabezado de respuesta para indicar que es un PDF
        // res.set({
        //     'Content-Type': 'application/pdf',
        //     'Content-Disposition': 'attachment; filename=file.pdf', // Opcional: nombre del archivo
        //     'Content-Length': data.length,
        // });

        // // Envía los bytes del PDF
        // res.send(data);

        // var condition = { id_contrato: id_contrato, id_estatus: id_estatus };
        // var registros = await model.count({ where: condition })

        // if (registros > 0) return res.status(400).send({ error: "ya existe registro con esos datos" });

        // await model.create({
        //     id_contrato: id_contrato,
        //     id_estatus: id_estatus
        // });

        // return res.status(200).send({ mensaje: "Registro almacenado exitosamente", error: "" });
    }
    catch (err) {
        return res.status(500).send({ error: "error: " + err.message })
    }
};



exports.sign = async (req, res) => {

    const t = await db.sequelize.transaction();

    try {

        let id_estatus = 3;

        let id_contrato = req.body.id_contrato || 0;
        let company = req.body.company || "";
        let address = req.body.address || "";
        let name = req.body.name || "";
        let position = req.body.position || "";
        let id = req.body.id || "";
        let country = req.body.country || "";
        let city = req.body.city || "";
        let state = req.body.state || "";
        let region = req.body.region || "";
        let ip = req.body.ip || "";

        if (id_contrato == 0) return res.status(400).send({ error: "input id_contract" });
        if (!isInteger(id_contrato)) return res.status(400).send({ error: "input valid integer in id_contract" });

        if (company == "") return res.status(400).send({ error: "input company's name" });
        if (address == "") return res.status(400).send({ error: "input company's address" });
        if (name == "") return res.status(400).send({ error: "input responsible name" });
        if (position == "") return res.status(400).send({ error: "input responsible position" });
        if (id == "") return res.status(400).send({ error: "input last 4 digits of responsible person's ID" });

        let contrato = await db.contrato.findOne({ where: { id_contrato: id_contrato } });
        if (!contrato) return res.status(404).send({ error: "it does not exist contract with id: " + id_contrato });

        let estatus = await db.estatus.findOne({ where: { id_estatus: id_estatus } });
        if (!estatus) return res.status(404).send({ error: "no existe estatus con id: " + id_estatus });

        let condition = { id_contrato: id_contrato, id_estatus: id_estatus };
        let registros = await model.count({ where: condition })

        if (registros > 0) return res.status(400).send({ error: "A record with this data already exists" });


        //actualizar contrato
        await db.contrato.update(
            {
                id_contrato: id_contrato,
                empresa: company.toUpperCase(),
                responsable: name.toUpperCase(),
                puesto: position.toUpperCase(),
                direccion: address.toUpperCase(),
                id: id.toUpperCase(),
                ciudad: city,
                region: region,
                estado: state,
                pais: country,
                ip: ip
            },
            {
                where: { id_contrato: id_contrato }
            },
            { transaccion: t }
        );


        //crear transaaccion
        await model.create({
            id_contrato: id_contrato,
            id_estatus: id_estatus
        }, { transaction: t });


        /*
        //crear pdf
        const fecha = new Date();
        const date = dayjs(fecha).format('YYYY-MM-DD HH:mm');
        const total = "USD $" + formatNumber(contrato.costo);
        var info = { name: company.toUpperCase(), address: address.toUpperCase(), date, total };

        var filePath = path.join(__dirname, '../public/templates/contract.html');
        var html = await ejs.renderFile(filePath, { info }, { async: true });

        let pdfResult = await generatePDF(html);
        if (pdfResult.error) return res.status(200).send({ error: pdfResult.error });

        //firmar electronicamente pdf
        let pdfBuffer = pdfResult.bytes;
        let rutaCliente = path.join(__dirname, "../public/img/8k-signature.jpg");
        if (!fs.existsSync(rutaCliente)) return res.status(400).send({ error: "it doesn't exist company logo" });

        const signedPdf = await FirmarPdfExtended(pdfBuffer, name.toUpperCase(), contrato.email, company.toUpperCase(), city, state, country, 10, 10, rutaCliente );

        //insertar documento en bucket
        const espacio = ambiente.current;
        const extension = ".pdf";
        const base64 = Buffer.from(signedPdf).toString('base64');
        const subfolder = 'codemakers/contratos';

        let bucketData = { ambiente: espacio, subfolder, base64, extension };
        let bucketResult = await postData("https://bucket.code-makers.com/upload-base64", bucketData);

        if (bucketResult.error) return res.status(400).send({ error: "Error en bucket: " + bucketResult.error });

        //insertar tabla documento
        let nombrePdf = randomText(8) + ".pdf";
        let ruta = bucketResult.file;

        await db.documento.create({
            nombre: nombrePdf,
            ruta: ruta,
            id_contrato: id_contrato,
        }, { transaction: t });
        */


        let message = await GetEmailMessage(estatus.id_estatus, estatus.nombre, contrato.codigo);
        let data = { token: "abc123", subject: "Notification", to: contrato.email, text: message, /*pdf: base64, nombre: nombrePdf*/ }
        let result = await postData("https://mailer.code-makers.com/mail", data);

        if (result.error != "") return res.status(400).send({ error: "Error to send email: " + result.error });

        await t.commit();

        return res.status(200).send({ mensaje: "record saved successfuly" });
    }
    catch (err) {
        await t.rollback();
        return res.status(500).send({ error: "error: " + err.message })
    }
};



async function GetEmailMessage(id, nombre, code) {

    let message = `<h2>Notification Message</h2>

    Please do not reply, this is an automated message from Codemakers LLC. <br/><br/>
    
    Your project has been updated to the following status: ${nombre} <br/><br/>
    
    Thank you for choosing our services.`;


    let message2 = `<h2>Notification Message</h2>

    Please do not reply, this is an automated message from Codemakers LLC. <br/><br/>

    Your project has been updated to the following status: ${nombre} <br/><br/>

    Please go to this link to verify and sign your contract: https://contracts.code-makers.com/smart?code=${code} <br/><br/>

    Thank you for choosing our services.`;
    //Please go to this link to verify and sign your contract: https://contracts-codemakers.onrender.com/smart?code=${code} <br/><br/>

    return await id == 2 ? message2 : message;
}



/*
//const PASSWORD = "sdodkdieidp";


async function firmarContrato22(pdfBuffer, signer1, signer2) {


    let fullName = signer1.fullName, company = signer1.company, city = signer1.city, state = signer1.state, country = signer1.country, email = signer1.email;
    const p12Buffer = generateP12BufferExtended(fullName, company, city, state, country)
    let location = city + ", " + country;

    //let pdfBuffer = fs.readFileSync(`c:/tmp/financial.pdf`)
    const lastPage = await getLastPage(pdfBuffer);
    let ruta = signer1.ruta;
    let xPos = signer1.xPos, yPos = signer1.yPos;

    const coppiedPdfBuffer = Buffer.from(pdfBuffer)

    const signatureOptions = {
        reason: 'Signed by ' + fullName,
        email: email,
        location: city + ", " + country,
        signerName: company,
        annotationOnPages: [lastPage],
        annotationAppearanceOptions: {
            signatureCoordinates: {
                left: xPos,
                bottom: yPos,
                right: xPos + 160,
                top: yPos + 60
            },
            imageDetails: {
                imagePath: ruta,
                transformOptions: { rotate: 0, space: 60, stretch: 40, tilt: 0, xPos: 0, yPos: 15 },
            },
            signatureDetails: [
                {
                    value: 'Signed by ' + fullName,
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 50 },
                },
                {
                    value: 'Reason: Signed',
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 40 },
                },
                {
                    value: `Date: ${formatDate()}`,
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 30 },
                },
                {
                    value: 'Location: ' + location,
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 20 },
                },
            ],
        },
    }

    const signedPdf = await sign(coppiedPdfBuffer, p12Buffer, "12345", signatureOptions)
    let ruta2 = signer2.ruta;
    xPos = signer2.xPos;
    fullName = signer2.fullName, company = signer2.company, city = signer2.city, state = signer2.state, country = signer2.state, email = signer2.email;
    location = city + ", " + country;

    const signatureOptions2 = {
        reason: 'Signed by ' + fullName,
        email: email,
        location: city + ", " + country,
        signerName: company,
        annotationOnPages: [lastPage],
        annotationAppearanceOptions: {
            signatureCoordinates: {
                left: xPos,
                bottom: yPos,
                right: xPos + 160,
                top: yPos + 60
            },
            imageDetails: {
                imagePath: ruta2,
                transformOptions: { rotate: 0, space: 60, stretch: 40, tilt: 0, xPos: 0, yPos: 15 },
            },
            signatureDetails: [
                {
                    value: 'Signed by ' + fullName,
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 50 },
                },
                {
                    value: 'Reason: Signed',
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 40 },
                },
                {
                    value: `Date: ${formatDate()}`,
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 30 },
                },
                {
                    value: 'Location: ' + location,
                    fontSize: 7,
                    transformOptions: { rotate: 0, space: 1, tilt: 0, xPos: 70, yPos: 20 },
                },
            ],
        },
    }


    const p12Buffer2 = generateP12BufferExtended(fullName, company, city, state, country)
    const signedPdfSecondly = await sign(signedPdf, p12Buffer2, "12345", signatureOptions2);

    if (fs.existsSync("c:/tmp/ass5.pdf"))
        fs.unlinkSync("c:/tmp/ass5.pdf")

    fs.writeFileSync("c:/tmp/ass5.pdf", signedPdfSecondly);

    return signedPdfSecondly;
}
*/