'use strict';

const Service = require('egg').Service;
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const queueName = 'test';
const cookiePath = '../public/data/cookies.json';

const validate = result => {
  if (result.code !== 2000) throw new Error(result && result.msg || '服务器异常');
  return result.data;
};

class HomeService extends Service {
  async getMails() {
    const { ctx } = this;
    const limit = 150;
    console.log(`${ctx.app.config.legal.host}/api/email/get/${limit}`);
    const { data: result } = await ctx.curl(`${ctx.app.config.legal.host}/api/email/get/${limit}`, {
      dataType: 'json',
      method: 'POST',
    });

    return validate(result);
  }

  async updateStatus(mails) {
    const { ctx } = this;
    console.log(`${ctx.app.config.legal.host}/api/email/callback`);
    const { data: result } = await ctx.curl(`${ctx.app.config.legal.host}/api/email/callback`, {
      contentType: 'json',
      dataType: 'json',
      method: 'POST',
      data: mails,
    });

    return validate(result);
  }

  async sendMail(mails) {
    const { ctx, service } = this;
    const result = [];
    const browserConfig = {
      args: [ '--no-sandbox', '--disable-setuid-sandbox' ],
      headless: true,
      defaultViewport: {
        width: 1024,
        height: 1000,
      },
    };
    let cookie = fs.readFileSync(path.join(__dirname, cookiePath)).toString();
    try {
      const browser = await puppeteer.launch(browserConfig);
      const page = await browser.newPage();
      if (cookie) await ctx.helper.addCookies(JSON.parse(cookie), page);
      await page.goto('https://exmail.qq.com');
      ctx.logger.info('tecent mail: 进入https://exmail.qq.com');
      const btnlogin = await page.$('.index_topbar_btn_login');
      const btlogin = await page.$('#btlogin');

      // 未登录状态先进行登录
      if (btnlogin || btlogin) {
        ctx.logger.info('tecent mail: 未登录进行登录');
        if (btnlogin) {
          await page.goto('https://exmail.qq.com/login');
          await page.click('.js_show_pwd_panel');
        }
        await page.$eval('#inputuin', input => { input.value = ''; });
        await page.type('#inputuin', ctx.app.config.tecent.account);
        await page.type('#pp', ctx.app.config.tecent.password);
        await page.click('#auto_login_in_five_days_pwd');
        await page.click('#btlogin');
        await page.waitForNavigation({ waitUntil: 'load' }); // 等待页面加载出来，等同于window.onload
        let VerifyArea = await page.$('#VerifyArea');
        if (VerifyArea) {
          let j = 0;
          ctx.logger.warn('tecent mail: 登录需要输入验证码!');
          while (VerifyArea && j < 100) {
            j++;
            ctx.logger.warn(`tecent mail: 第${j}次输入验证码!`);
            await ctx.helper.writeTecentLoginCode(page);
            await page.waitFor(5000);
            VerifyArea = await page.$('#VerifyArea');
          }
          if (j === 100) throw new Error('验证码尝试过多');
        }
        cookie = await page.cookies('https://exmail.qq.com');
        fs.writeFileSync(path.join(__dirname, cookiePath), JSON.stringify(cookie));
      }
      ctx.logger.info('tecent mail: 已登录');
      for (let i = 0; i < mails.length; i++) {
        const email = mails[i].email;
        ctx.logger.info(`tecent mail: 准备发送第${i + 1}封邮件 mail: ${email}`);
        await page.click('#composebtn');
        const mainFrame = await page.frames().find(f => f.name() === 'mainFrame');
        await mainFrame.waitFor(3000);
        await mainFrame.waitFor('#subject');
        await mainFrame.waitFor('.addr_text>input');
        await mainFrame.type('.addr_text>input', email);
        await mainFrame.type('#subject', mails[i].subject);
        const bodyFrame = await mainFrame.childFrames()[2];
        await bodyFrame.type('body', mails[i].content);
        await mainFrame.click('input[name="sendbtn"]');

        await mainFrame.waitFor(3000);
        const isNeedCode = await page.$('#QMVerify_s_vfcode');
        if (isNeedCode) throw new Error('发送邮件需要输入验证码！');

        await mainFrame.waitFor('#readSendbox>a');
        await mainFrame.click('#readSendbox>a');
        await mainFrame.waitFor(5000);
        const mailSendStatusFrame = await mainFrame.childFrames().find(f => f.name() === 'mailSendStatus');
        await mailSendStatusFrame.waitFor('#statusbtn');
        await mailSendStatusFrame.waitFor('#clickstu');
        await mailSendStatusFrame.click('#clickstu');
        let sendStatus = await mailSendStatusFrame.$eval('#statusbtn', el => el.innerHTML);
        const receiver = await mailSendStatusFrame.$eval('.oneline', el => el.innerHTML);
        if (sendStatus === '正在投递') {
          await mailSendStatusFrame.waitFor(10000);
          const clickStatus = await mailSendStatusFrame.$eval('#clickstu', el => el.innerHTML);
          if (clickStatus === '[查看详情]') await mailSendStatusFrame.click('#clickstu');
          await mailSendStatusFrame.click('#refreshbutton');
          await mailSendStatusFrame.waitFor(2000);
          sendStatus = await mailSendStatusFrame.$eval('#statusbtn', el => el.innerHTML);
        }

        if (!receiver.includes(email)) {
          ctx.logger.error('收件箱不一致, 投递失败');
          continue;
        }

        if (sendStatus !== '投递成功') {
          ctx.logger.error(sendStatus || '投递失败');
          continue;
        }

        await page.mouse.move(0, 0);
        const mainFrameContainer = await page.$('#mainFrameContainer');
        const imageName = `${email}_${Date.now()}.png`;
        await mainFrameContainer.screenshot({ path: `./app/public/images/${imageName}` });
        const imagePath = await service.fdfs.upload(path.join(__dirname, `../public/images/${imageName}`));
        result.push({ id: mails[i].id, url: imagePath });
        await mainFrame.waitFor(parseInt((Math.random() * 3 + 1) * 1000, 10));
      }
      await browser.close();
    } catch (e) {
      await service.dingTalk.push(e && e.message);
      ctx.logger.error(e);
    }
    return result;
  }

  async publisher() {
    const ch = await this.app.amqplib.createChannel();
    await ch.assertQueue(queueName, { durable: false });
    for (let i = 0; i < 5; i++) {
      await ch.sendToQueue(queueName, Buffer.from(`第${i}条消息`));
    }
    await ch.close();
  }

  async consumer() {
    let ch;
    try {
      ch = await this.app.amqplib.createChannel();
      await ch.assertQueue(queueName, { durable: false });
      await ch.prefetch(1, false);
      let i = 0;
      await ch.consume(queueName, msg => {
        try {
          i++;
          console.log('consumer', msg.content.toString());
          if (i === 1) { throw new Error('出现异常'); }
          ch.ack(msg);
        } catch (err) {
          this.ctx.logger.error(err);
          ch.close();
        }
      }, { noAck: false });
    } catch (err) {
      this.ctx.logger.error(err);
      if (ch) ch.close();
    }
  }
}

module.exports = HomeService;
