
import express, { Request, Response } from 'express';
import nodemailer from 'nodemailer';
import dotenv from 'dotenv';
import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';

dotenv.config();

const app = express();
app.use(express.json());

const PORT = Number(process.env.PORT || 3000);
const PUBLIC_URL = process.env.PUBLIC_URL!;

const DATA_PATH = path.join(process.cwd(), 'email-tracking');
const SENT_PATH = path.join(DATA_PATH, 'sent.json');
const OPEN_PATH = path.join(DATA_PATH, 'opened.json');

// SMTP
const transporter = nodemailer.createTransport({
    host: process.env.SMTP_HOST,
    port: Number(process.env.SMTP_PORT || 587),
    secure: Number(process.env.SMTP_PORT) === 465,
    auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS
    }
});

interface SentEmail {
    id: string;
    token: string;
    recipient: string;
    subject: string;
    sentAt: string;
}

interface EmailOpen {
    emailId: string;
    openedAt: string;
    ipAddress: string;
    userAgent: string;
}

// Arquivos JSON
async function ReadJson<T>(filePath: string): Promise<T[]> {
    try {
        return JSON.parse(await fs.readFile(filePath, 'utf8'));
    } catch {
        return [];
    }
}

async function SaveJson<T>(filePath: string, data: T[]): Promise<void> {
    await fs.mkdir(DATA_PATH, { recursive: true });
    await fs.writeFile(filePath, JSON.stringify(data, null, 4));
}

// Enviar e-mail
async function SendEmail(
    recipient: string,
    subject: string,
    content: string
): Promise<string> {

    const id = crypto.randomUUID();
    const token = crypto.randomBytes(32).toString('hex');

    const trackingUrl = `${PUBLIC_URL}/email/open/${token}`;

    const html = `
        <!DOCTYPE html>
        <html>
            <body>
                ${content}

                <img
                    src="${trackingUrl}"
                    width="1"
                    height="1"
                    alt=""
                    style="display:none"
                />
            </body>
        </html>
    `;

    const info = await transporter.sendMail({
        from: process.env.SMTP_FROM,
        to: recipient,
        subject,
        html
    });

    const sentEmails = await ReadJson<SentEmail>(SENT_PATH);

    sentEmails.push({
        id,
        token,
        recipient,
        subject,
        sentAt: new Date().toISOString()
    });

    await SaveJson(SENT_PATH, sentEmails);

    console.log('E-mail enviado:', info.messageId);

    return id;
}

// Endpoint de rastreamento
app.get('/email/open/:token', async (req: Request, res: Response) => {
    try {
        const { token } = req.params;

        const sentEmails = await ReadJson<SentEmail>(SENT_PATH);

        const email = sentEmails.find(item => item.token === token);

        if (email) {
            const openedEmails = await ReadJson<EmailOpen>(OPEN_PATH);

            openedEmails.push({
                emailId: email.id,
                openedAt: new Date().toISOString(),
                ipAddress: req.ip || '',
                userAgent: req.get('user-agent') || ''
            });

            await SaveJson(OPEN_PATH, openedEmails);

            console.log('Abertura registrada:', email.recipient);
        }

        // Imagem GIF transparente de 1x1 pixel
        const pixel = Buffer.from(
            'R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=',
            'base64'
        );

        res.set({
            'Content-Type': 'image/gif',
            'Content-Length': pixel.length,
            'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
            'Pragma': 'no-cache'
        });

        res.status(200).end(pixel);

    } catch (error) {
        console.error('Erro ao registrar abertura:', error);
        res.sendStatus(500);
    }
});

// Consultar aberturas de um e-mail
app.get('/email/:id/opens', async (req: Request, res: Response) => {
    const sentEmails = await ReadJson<SentEmail>(SENT_PATH);

    const email = sentEmails.find(item => item.id === req.params.id);

    if (!email) {
        res.sendStatus(404);
        return;
    }

    const openedEmails = await ReadJson<EmailOpen>(OPEN_PATH);

    const result = openedEmails.filter(
        item => item.emailId === email.id
    );

    res.json({
        email,
        totalOpens: result.length,
        opens: result
    });
});

// Inicialização
async function Start(): Promise<void> {
    await fs.mkdir(DATA_PATH, { recursive: true });

    app.listen(PORT, async () => {
        console.log(`Servidor iniciado na porta ${PORT}`);

        try {
            await transporter.verify();
            console.log('Conexão SMTP validada.');

            // Exemplo de envio
            const emailId = await SendEmail(
                'destinatario@hotmail.com',
                'Teste de rastreamento',
                `
                    <h2>Olá!</h2>
                    <p>Este é um e-mail de teste.</p>
                    <p>Estamos testando o rastreamento de abertura.</p>
                `
            );

            console.log('ID do e-mail:', emailId);

        } catch (error) {
            console.error('Erro:', error);
        }
    });
}

Start();
