/**
 * 參考:
 * NPOI 套件
 * SharpZipLib
 * MailKit  https://github.com/jstedfast/MailKit
 * MailKit轉寄信件 https://stackoverflow.com/questions/29414995/forward-email-using-mailkit-c
 * **/

using System;
using MailKit.Net.Smtp;
using MailKit;
using MimeKit;
using MailKit.Net.Imap;
using MailKit.Security;
using System.Linq;
using System.Text.RegularExpressions;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using FolderZipper;
using MimeKit.Tnef;
using OpenMcdf;
using System.Collections.Generic;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System.Threading;

namespace TurnkeyMailChecker
{
    class Program
    {

        private static MailboxAddress sender = new MailboxAddress(Properties.Settings.Default.mailUser, String.Format("{0}@{1}", Properties.Settings.Default.mailUser, Properties.Settings.Default.mailServer));
        private static String mailServer = Properties.Settings.Default.mailServer;
        private static String mailUser = Properties.Settings.Default.mailUser;
        private static String mailUserPwd = Properties.Settings.Default.mailUserPwd;

        private static void timerC(object state)
        {
            Environment.Exit(0);
        }
        public static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("檢核開始");
                checkMail();
            }
            catch (Exception ex) {
                Console.Write(ex.Message);
                sendErrorMail(ex.Message);
            }

            Console.WriteLine("檢核結束,10秒後自動關閉程式");
            Timer t = new Timer(timerC, null, 10000, 10000);
            Console.ReadLine();
        }

        private static void checkMail() {


            if (!Directory.Exists(Properties.Settings.Default.inboxDir))
                Directory.CreateDirectory(Properties.Settings.Default.inboxDir);

            using (var IMAPclient = new ImapClient())
            {
                IMAPclient.Connect(mailServer, 143, SecureSocketOptions.None);
                IMAPclient.Authenticate(mailUser, mailUserPwd);

                // The Inbox folder is always available on all IMAP servers...
                var inbox = IMAPclient.Inbox;
                inbox.Open(FolderAccess.ReadWrite);

                Console.WriteLine("總信件數: {0}", inbox.Count);
                Console.WriteLine("未讀信件: {0}", inbox.Recent);

                foreach (var summary in inbox.Fetch(0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure))
                {
                    var message = inbox.GetMessage(summary.UniqueId);

                    var fromAddress = message.From.Mailboxes.First().Address;
                    var subject = message.Subject;
                    Console.WriteLine("寄件者: {0}", fromAddress);
                    Console.WriteLine("主旨: {0}", subject);

                    Regex regx = new Regex(String.Format("{0}{1}", Properties.Settings.Default.companyName, @"\d{4}-\d{2}-\d{2}歷史存證檢核表"));

                    //從發票平台寄出的歷史存證檢核表 才檢查
                    if (fromAddress == Properties.Settings.Default.turnkeyMail && regx.IsMatch(subject))
                    {
                        String filename = DateTime.Now.ToString("yyyyMMddHHmmssfff");
                        String zip_path = String.Format("./{0}/{1}.zip", Properties.Settings.Default.inboxDir, filename);
                        using (var file = new FileStream(zip_path, FileMode.OpenOrCreate, FileAccess.Write))
                        {
                            foreach (var attachement in message.Attachments)
                            {
                                if (attachement.GetType() == typeof(TnefPart)) //用outlook測試轉寄信turnkey時會是 tnef的格式
                                {
                                    TnefPart tnefPart = (TnefPart)attachement;

                                    MimeMessage tnefMessage = tnefPart.ConvertToMessage();
                                    var multipart = (IEnumerable<dynamic>)tnefMessage.Body;

                                    foreach (var m in multipart)
                                    {
                                        if (((MimeEntity)m).ContentType.MimeType == "application/zip")
                                        {
                                            ((MimeContent)m.Content).WriteTo(file);
                                        }
                                    }
                                }
                                else if (attachement.GetType() == typeof(MimePart)) //turnkey寄出的會是MimePart格式
                                {
                                    MimePart mimePart = (MimePart)attachement;
                                    mimePart.Content.DecodeTo(file);
                                }
                            }
                        }

                        //解壓附件
                        String unzip_path = String.Format("{0}/{1}" , Properties.Settings.Default.inboxDir, filename);
                        using (var file = new FileStream(zip_path, FileMode.Open, FileAccess.Read))
                        {
                            ZipUtil.UnZipFiles(file, unzip_path, "");
                        }

                        foreach (var tmpFilePath in Directory.GetFiles(unzip_path, "*.xls", SearchOption.AllDirectories))
                        {
                            HSSFWorkbook hSSFWorkbook;
                            using (FileStream fs = new FileStream(tmpFilePath, FileMode.Open, FileAccess.Read))
                            {
                                hSSFWorkbook = new HSSFWorkbook(fs);
                            }

                            //傳輸比對
                            ISheet sheet = hSSFWorkbook.GetSheetAt(0);
                            var sheetRow = sheet.GetRow(4);
                            var sendDiffCnt = sheetRow.GetCell(9).NumericCellValue;//傳輸差異數
                            var storageDiffCnt = sheetRow.GetCell(10).NumericCellValue;//存證差異數

                            //存證異常清單
                            int abnormal_cnt = 0;
                            sheet = hSSFWorkbook.GetSheetAt(2);
                            bool headerFound = false;
                            for (int row = 0; row <= sheet.LastRowNum; row++)
                            {
                                sheetRow = sheet.GetRow(row);
                                if (sheetRow == null) continue;
                                var cell = sheetRow.GetCell(0);

                                if (!headerFound && cell.StringCellValue == "送方統編")
                                {
                                    headerFound = true;
                                    continue;
                                }

                                if (headerFound)
                                    if (sheetRow != null) abnormal_cnt++;
                            }
                            if (!headerFound)
                                throw new Exception("存證異常清單表頭異常!");

                            if (sendDiffCnt > 0 || storageDiffCnt > 0 || abnormal_cnt > 0)
                            {
                                String chkResultMsg = String.Format("異常,請檢查!傳輸差異數:{0}, 存證差異數:{1},存證異常清單筆數:{2}", sendDiffCnt, storageDiffCnt, abnormal_cnt);

                                Console.WriteLine(chkResultMsg);

                                forwardMail(message, chkResultMsg);
                            }
                        }

                        Directory.Delete(unzip_path, true);
                        File.Delete(zip_path);
                    }

                    //處理完後就刪除郵件
                    inbox.Store(summary.UniqueId, new StoreFlagsRequest(StoreAction.Add, MessageFlags.Deleted) { Silent = true });
                    inbox.Expunge();

                }
                IMAPclient.Disconnect(true);
            }

        }


        public static void sendErrorMail(String bodyMsg)
        {
            var message = new MimeMessage();
            message.From.Add(sender);

            var misMails = Properties.Settings.Default.misMails.Split(';');
            foreach (var m in misMails)
            {
                var user = m.Split(',');
                message.To.Add(new MailboxAddress(user[0], user[1]));
                break;
            }

            message.Subject = "電子發票檢核歷史存證郵件時發生錯誤" + DateTime.Now.ToString("yyyyMMddHHmmss");

            // now to create our body...
            var builder = new BodyBuilder();
            builder.TextBody = bodyMsg;

            message.Body = builder.ToMessageBody();

            using (var client = new SmtpClient())
            {
                client.Connect(mailServer, 25, SecureSocketOptions.None);
                client.Authenticate(mailUser, mailUserPwd);

                client.Send(message);

                client.Disconnect(true);
            }
        }

        public static void forwardMail(MimeMessage messageToForward, String bodyMsg)
        {
            var message = new MimeMessage();
            message.From.Add(sender);

            var misMails = Properties.Settings.Default.misMails.Split(';');
            foreach (var m in misMails)
            {
                var user = m.Split(',');
                message.To.Add(new MailboxAddress(user[0], user[1]));
                break;
            }           

            message.Subject = "FWD: " + messageToForward.Subject;

            var builder = new BodyBuilder();
            builder.TextBody = bodyMsg;
            builder.Attachments.Add(new MessagePart { Message = messageToForward });

            message.Body = builder.ToMessageBody();

            using (var client = new SmtpClient())
            {
                client.Connect(mailServer, 25, SecureSocketOptions.None);
                client.Authenticate(mailUser, mailUserPwd);

                client.Send(message);

                client.Disconnect(true);
            }
        }
        
        
    }
}