import axios from 'axios';
import { google } from 'googleapis';
import fs from 'node:fs';
import https from 'https';
const clientId = process.env.GOOGLE_CLIENT_ID;
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
// Function to create a Gmail client
const createGmailClient = accessToken => {
  const oauth2Client = new google.auth.OAuth2();
  oauth2Client.setCredentials({ access_token: accessToken });
  return google.gmail({ version: 'v1', auth: oauth2Client });
};

// Function to exchange refresh token for new access token
const refreshAccessToken = async refreshToken => {
  const tokenEndpoint = 'https://oauth2.googleapis.com/token';
  const params = new URLSearchParams();
  params.append('refresh_token', refreshToken);
  params.append('client_id', clientId);
  params.append('client_secret', clientSecret);
  params.append('grant_type', 'refresh_token');

  const response = await axios.post(tokenEndpoint, params);
  return response.data.access_token;
};

const getGmail = async (access_token, displayName) => {
  try {
    const res = await axios.get('https://www.googleapis.com/oauth2/v2/userinfo', {
      headers: { Authorization: `Bearer ${access_token}` },
    });

    const gmail = res.data.email;
    return `${displayName} <${gmail}>`;
  } catch (err) {
    console.log('gmail retrive error ', err);
    return displayName;
  }
};
// Function to create a raw email message
const makeEmail = async (
  to,
  from,
  subject,
  html,
  url,
  pdfName,
  bcc,
  cc,
  filename,
  certificatePath,
  replyto,
  testPdf
) => {
  const htmlContent = html;
  const boundary = 'boundary_' + Date.now().toString(16);
  const bccHeader = bcc && bcc.length > 0 ? `BCC: ${bcc.join(',')}\n` : ''; // Construct BCC header if provided
  const ccHeader = cc && cc.length > 0 ? `CC: ${cc.join(',')}\n` : ''; // Construct CC header if provided
  const replyToHeader = replyto ? `Reply-To: ${replyto}\n` : ''; // Construct Reply-To header if provided

  let str;
  if (url) {
    let attachments;
    let Pdf = fs.createWriteStream(testPdf);
    const writeToLocalDisk = () => {
      return new Promise((resolve, reject) => {
        const isSecure =
          new URL(url)?.protocol === 'https:' && new URL(url)?.hostname !== 'localhost';
        if (isSecure) {
          https
            .get(url, async function (response) {
              response.pipe(Pdf);
              Pdf.on('finish', () => resolve('success'));
              Pdf.on('error', () => resolve('error'));
            })
            .on('error', e => {
              console.error(`error: ${e.message}`);
              resolve('error');
            });
        } else {
          const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
          axios
            .get(url, { responseType: 'stream', httpsAgent })
            .then(response => {
              response.data.pipe(Pdf);
              Pdf.on('finish', () => resolve('success'));
              Pdf.on('error', () => resolve('error'));
            })
            .catch(e => {
              console.log('error', e.message);
              resolve('error');
            });
        }
      });
    };
    // `writeToLocalDisk` is used to create pdf file from doc url
    const ress = await writeToLocalDisk();
    if (ress) {
      const file = {
        filename: filename || `${pdfName}.pdf` || 'exported.pdf',
        type: 'application/pdf',
        path: Pdf.path,
      };

      //  `certificateBuffer` used to create buffer from pdf file
      try {
        const certificate = {
          filename: 'certificate.pdf',
          type: 'application/pdf',
          path: certificatePath || './exports/certificate.pdf',
        };
        if (fs.existsSync(certificate.path)) {
          attachments = [file, certificate];
        } else {
          attachments = [file];
        }
      } catch (err) {
        attachments = [file];
        console.log('sendMailGmailProvider read certificate error', err);
      }
    }
    const attachmentParts = attachments.map(attachment => {
      const content = fs.readFileSync(attachment.path);
      const encodedContent = content.toString('base64');
      return [
        `Content-Type: ${attachment.type}\n`,
        'MIME-Version: 1.0\n',
        `Content-Disposition: attachment; filename="${attachment.filename}"\n`,
        `Content-Transfer-Encoding: base64\n\n`,
        `${encodedContent}\n`,
      ].join('');
    });

    const attachmentBody = attachmentParts.join(`\n--${boundary}\n`);

    str = [
      'Content-Type: multipart/mixed; boundary="' + boundary + '"\n',
      'MIME-Version: 1.0\n',
      `To: ${to}\n`,
      `From: ${from}\n`,
      bccHeader,
      ccHeader,
      replyToHeader,
      `Subject: ${subject}\n\n`,
      '--' + boundary + '\n',
      'Content-Type: text/html; charset="UTF-8"\n',
      'MIME-Version: 1.0\n\n',
      `${htmlContent}\n\n`,
      `\n--${boundary}\n`,
      attachmentBody,
      '--' + boundary + '--',
    ].join('');
  } else {
    str = [
      'Content-Type: multipart/mixed; boundary="' + boundary + '"\n',
      'MIME-Version: 1.0\n',
      `To: ${to}\n`,
      `From: ${from}\n`,
      bccHeader,
      ccHeader,
      replyToHeader,
      `Subject: ${subject}\n\n`,
      '--' + boundary + '\n',
      'Content-Type: text/html; charset="UTF-8"\n',
      'MIME-Version: 1.0\n\n',
      `${htmlContent}\n\n`,
      '--' + boundary + '--',
    ].join('');
  }

  const encodedMail = Buffer.from(str).toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
  return encodedMail;
};
export default async function sendMailGmailProvider(_extRes, template) {
  const {
    sender,
    receiver,
    subject,
    html,
    url,
    pdfName,
    bcc,
    cc,
    filename,
    certificatePath,
    replyto,
  } = template;

  if (_extRes) {
    let refresh_token = '';
    refresh_token = _extRes?.TenantId?.google_refresh_token;
    // generate access token
    const access_token = await refreshAccessToken(refresh_token);

    try {
      // Construct email message
      const displayName = sender || _extRes.Email || 'me';
      const from = await getGmail(access_token, displayName);
      const to = receiver;
      const randomNumber = Math.floor(Math.random() * 5000);
      const testPdf = `test_${randomNumber}.pdf`;
      const email = await makeEmail(
        to,
        from,
        subject,
        html,
        url,
        pdfName,
        bcc,
        cc,
        filename,
        certificatePath,
        replyto,
        testPdf
      );
      // Update Gmail client with new access token
      const newGmail = createGmailClient(access_token);
      // sending email with new client
      const response = await newGmail.users.messages.send({
        userId: 'me',
        requestBody: { raw: email },
      });
      console.log('gmail provider res: ', response?.status);
      const certificatepath = certificatePath || './exports/certificate.pdf';
      if (fs.existsSync(certificatepath)) {
        try {
          fs.unlinkSync(certificatepath);
        } catch (err) {
          console.log('Err in unlink certificate sendmailgmail provider');
        }
      }
      if (fs.existsSync(testPdf)) {
        try {
          fs.unlinkSync(testPdf);
        } catch (err) {
          console.log('sendMailGmailProvider unlink pdf error');
        }
      }
      return { code: 200, message: 'Email sent successfully' };
    } catch (error) {
      const message = error?.response?.data || error?.message || 'Unknown error';
      console.error('Error sending email:', message);
      return { code: 500, message: 'Failed to send email ' + error };
    }
  }
}
