using IRaCIS.Core.Domain.Share;
using MimeKit;
using IRaCIS.Core.Application.Helper;
using MailKit;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Application.Auth;
using AutoMapper;
using IRaCIS.Application.Contracts;
using Nito.AsyncEx;
using Microsoft.Extensions.Options;

namespace IRaCIS.Application.Services
{
    public interface IMailVerificationService
    {

        Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode);

        Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode);

        Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode);

        Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl);

        Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456");

        Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl);

        Task ExternalUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl);

        Task<Guid> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl);


    }

    public class MailVerificationService : IMailVerificationService
    {
        private readonly IRepository<VerificationCode> _verificationCodeRepository;

        private readonly IRepository<SystemBasicData> _systemBasicDatarepository;

        private readonly IWebHostEnvironment _hostEnvironment;
        private readonly IRepository<User> _userRepository;

        private readonly ITokenService _tokenService;

        private readonly IMapper _mapper;

        private readonly IRepository<Trial> _trialRepository;
        private readonly IRepository<UserType> _userTypeRepository;

        private readonly IRepository<Doctor> _doctorTypeRepository;

        private readonly AsyncLock _mutex = new AsyncLock();

        private readonly SystemEmailSendConfig _systemEmailConfig;



        public MailVerificationService(IRepository<VerificationCode> verificationCodeRepository,
            IRepository<SystemBasicData> systemBasicDatarepository,
            IWebHostEnvironment hostEnvironment,
            IRepository<User> userRepository,
            ITokenService tokenService,
            IRepository<Trial> trialRepository,
             IRepository<UserType> userTypeRepository,
             IRepository<Doctor> doctorTypeRepository,
            IMapper mapper, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig)
        {
            _systemEmailConfig = systemEmailConfig.CurrentValue;
            _verificationCodeRepository = verificationCodeRepository;
            _systemBasicDatarepository = systemBasicDatarepository;

            _hostEnvironment = hostEnvironment;

            _mapper = mapper;

            _tokenService = tokenService;
            _userRepository = userRepository;
            _trialRepository = trialRepository;

            _userTypeRepository = userTypeRepository;
            _doctorTypeRepository = doctorTypeRepository;

        }

        //重置邮箱 
        public async Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode)
        {



            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(userName, emailAddress));
            //主题
            messageToSend.Subject = "[来自展影IRC] 关于重置邮箱的提醒";

            var builder = new BodyBuilder();


            var pathToFile = _hostEnvironment.WebRootPath
                          + Path.DirectorySeparatorChar.ToString()
                          + "EmailTemplate"
                          + Path.DirectorySeparatorChar.ToString()
                          + "UserOptCommon.html";

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();


                builder.HtmlBody = string.Format(templateInfo,
                    $" 尊敬的 {userName} , ",
                    "您正在进行邮箱重置操作",
                    verificationCode
                    );
            }


            messageToSend.Body = builder.ToMessageBody();



            EventHandler<MessageSentEventArgs> sucessHandle = (sender, args) =>
          {
              // args.Response 
              var code = verificationCode.ToString();
              _ = _verificationCodeRepository.AddAsync(new VerificationCode()
              {
                  CodeType = 0,
                  HasSend = true,
                  Code = code,
                  UserId = userId,
                  ExpirationTime = DateTime.Now.AddMinutes(3)
              }).Result;
              _ = _verificationCodeRepository.SaveChangesAsync().Result;

          };


            await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle);


        }



        //不登录  通过邮箱重置密码
        public async Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode)
        {
            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress));
            //主题
            messageToSend.Subject = "[来自展影IRC] 关于重置密码的提醒";



            var builder = new BodyBuilder();

            var pathToFile = _hostEnvironment.WebRootPath
                        + Path.DirectorySeparatorChar.ToString()
                        + "EmailTemplate"
                        + Path.DirectorySeparatorChar.ToString()
                        + "UserOptCommon.html";

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();


                builder.HtmlBody = string.Format(templateInfo,
                    "",
                   "您正在进行邮箱重置密码操作",
                    verificationCode
                    );
            }



            messageToSend.Body = builder.ToMessageBody();


            EventHandler<MessageSentEventArgs> sucessHandle = (sender, args) =>
             {
                 var code = verificationCode.ToString();
                 _ = _verificationCodeRepository.AddAsync(new VerificationCode()
                 {
                     CodeType = Core.Domain.Share.VerifyType.Email,
                     HasSend = true,
                     Code = code,
                     UserId = Guid.Empty,//此时不知道用户
                     EmailOrPhone = emailAddress,
                     ExpirationTime = DateTime.Now.AddMinutes(3)
                 }).Result;
                 _ = _verificationCodeRepository.SaveChangesAsync().Result;
             };



            await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle);
        }

        //中心调研 登陆
        public async Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode)
        {


            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress));
            //主题
            messageToSend.Subject = $"[来自展影IRC] [{researchProgramNo}] 关于中心调研的提醒";




            var builder = new BodyBuilder();

            var pathToFile = _hostEnvironment.WebRootPath
                      + Path.DirectorySeparatorChar.ToString()
                      + "EmailTemplate"
                      + Path.DirectorySeparatorChar.ToString()
                      + "UserOptCommon.html";

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();


                builder.HtmlBody = string.Format(templateInfo,
                    "",
                   "您正在参与展影医疗IRC项目中心调研工作",
                    verificationCode
                    );
            }

            messageToSend.Body = builder.ToMessageBody();



            EventHandler<MessageSentEventArgs> sucessHandle = (sender, args) =>
            {
                // args.Response 
                var code = verificationCode.ToString();
                _ = _verificationCodeRepository.AddAsync(new VerificationCode()
                {
                    CodeType = VerifyType.Email,
                    HasSend = true,
                    Code = code,
                    UserId = Guid.Empty,//此时不知道用户
                    EmailOrPhone = emailAddress,
                    ExpirationTime = DateTime.Now.AddMinutes(3)
                }).Result;
                _ = _verificationCodeRepository.SaveChangesAsync().Result;
            };



            await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig,sucessHandle);


        }



        //添加用户发送邮件
        public async Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl)
        {

            var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();


            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail));
            //主题
            messageToSend.Subject = "[来自展影IRC] 关于创建账户的提醒";



            var builder = new BodyBuilder();

            var pathToFile = _hostEnvironment.WebRootPath
                        + Path.DirectorySeparatorChar.ToString()
                        + "EmailTemplate"
                        + Path.DirectorySeparatorChar.ToString()
                        + "AdminAddUser.html";

            var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map<UserBasicInfo>(sysUserInfo)));

            await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token });

            routeUrl = routeUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token;

            var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));

            var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();


                builder.HtmlBody = string.Format(templateInfo,
                   sysUserInfo.FullName,
                   sysUserInfo.UserName,
                   sysUserInfo.UserTypeRole.UserTypeShortName,
                    redirectUrl
                    );
            }



            messageToSend.Body = builder.ToMessageBody();


            await SendEmailHelper.SendEmailAsync(messageToSend,_systemEmailConfig);
        }

        //管理员重置密码发送邮件
        public async Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456")
        {
            var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();

            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail));
            //主题
            messageToSend.Subject = "[来自展影IRC] 关于重置账户密码的提醒";



            var builder = new BodyBuilder();

            var pathToFile = _hostEnvironment.WebRootPath
                        + Path.DirectorySeparatorChar.ToString()
                        + "EmailTemplate"
                        + Path.DirectorySeparatorChar.ToString()
                        + "AdminResetUser.html";


            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();


                builder.HtmlBody = string.Format(templateInfo,
                   sysUserInfo.FullName,
                   sysUserInfo.UserName,
                   sysUserInfo.UserTypeRole.UserTypeShortName,
                   pwdNotMd5
                    );
            }



            messageToSend.Body = builder.ToMessageBody();


            await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
        }


        //Site调研 用户加入项目
        public async Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl)
        {
            var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();

            var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);

            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail));
            //主题
            messageToSend.Subject = $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";



            var builder = new BodyBuilder();


            var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map<UserBasicInfo>(sysUserInfo)));

            if (sysUserInfo.IsFirstAdd)
            {
                await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token });
            }


            var pathToFile = _hostEnvironment.WebRootPath
                     + Path.DirectorySeparatorChar.ToString()
                     + "EmailTemplate"
                     + Path.DirectorySeparatorChar.ToString()
                     + (sysUserInfo.IsFirstAdd ? "TrialUserFirstJoin.html" : "TrialUserExistJoin.html");

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();

                var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token;

                var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));

                var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";

                builder.HtmlBody = string.Format(templateInfo,
                    sysUserInfo.FullName,
                    trialInfo.ExperimentName,
                    trialInfo.ResearchProgramNo,
                    trialInfo.TrialCode,
                    sysUserInfo.UserName,
                    sysUserInfo.UserTypeRole.UserTypeShortName,
                    sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl
                    );
            }

            messageToSend.Body = builder.ToMessageBody();

            await SendEmailHelper.SendEmailAsync(messageToSend,  _systemEmailConfig,null);


        }

        //外部用户 加入项目
        public async Task ExternalUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl)
        {
            var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException();

            var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();


            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(String.Empty, sysUserInfo.EMail));
            //主题
            messageToSend.Subject = $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";


            var builder = new BodyBuilder();



            var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map<UserBasicInfo>(sysUserInfo)));
            if (sysUserInfo.IsFirstAdd)
            {
                await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token });
            }

            var pathToFile = _hostEnvironment.WebRootPath
                        + Path.DirectorySeparatorChar.ToString()
                        + "EmailTemplate"
                        + Path.DirectorySeparatorChar.ToString()
                        + (sysUserInfo.IsFirstAdd ? "TrialUserFirstJoin.html" : "TrialUserExistJoin.html");

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();

                var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));

                var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token;

                var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";

                builder.HtmlBody = string.Format(templateInfo,
                    sysUserInfo.FullName,
                    trialInfo.ExperimentName,
                    trialInfo.ResearchProgramNo,
                    trialInfo.TrialCode,
                   sysUserInfo.UserName,
                    sysUserInfo.UserTypeRole.UserTypeShortName,
                   sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl
                    );
            }



            messageToSend.Body = builder.ToMessageBody();


            await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);

        }


        //医生生成账号加入  或者已存在账号加入到项目中
        public async Task<Guid> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl)
        {
            var doctor = await _doctorTypeRepository.FindAsync(doctorId);
            User sysUserInfo = null;

            var userType = await _userTypeRepository.FirstAsync(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer);

            using (await _mutex.LockAsync())
            {
                var isDoctorHaveAccount = await _userRepository.AnyAsync(t => t.DoctorId == doctorId);


                if (!isDoctorHaveAccount)
                {

                    var saveItem = new User() { FirstName = doctor.FirstName, LastName = doctor.LastName, EMail = doctor.EMail };

                    saveItem.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1;

                    saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User));

                    saveItem.UserName = saveItem.UserCode;

                    saveItem.UserTypeEnum = UserTypeEnum.IndependentReviewer;

                    saveItem.DoctorId = doctorId;
                    saveItem.UserTypeId = userType.Id;

                    var savedUser = await _userRepository.AddAsync(saveItem);

                    //下面获取Token 需要这部分信息
                    sysUserInfo = savedUser.Clone();

                    sysUserInfo.UserTypeRole = userType;

                    await _userRepository.SaveChangesAsync();

                }
                else
                {
                    sysUserInfo = (await _userRepository.Where(t => t.DoctorId == doctorId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();
                }
            }


            var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);

            var messageToSend = new MimeMessage();
            //发件地址
            messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
            //收件地址
            messageToSend.To.Add(new MailboxAddress(doctor.FullName, doctor.EMail));
            //主题
            messageToSend.Subject = $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";


            var builder = new BodyBuilder();


            var basicInfo = IRaCISClaims.Create(_mapper.Map<UserBasicInfo>(sysUserInfo));

            ////第一次添加的时候  注意赋值
            //basicInfo.PermissionStr = userType.PermissionStr;
            //basicInfo.UserTypeShortName = userType.UserTypeShortName;

            var token = _tokenService.GetToken(basicInfo);

            if (sysUserInfo.IsFirstAdd)
            {
                await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token });
            }


            var pathToFile = _hostEnvironment.WebRootPath
                     + Path.DirectorySeparatorChar.ToString()
                     + "EmailTemplate"
                     + Path.DirectorySeparatorChar.ToString()
                     + (sysUserInfo.IsFirstAdd ? "TrialDoctorFirstJoin.html" : "TrialDoctorExistJoin.html");

            using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
            {
                var templateInfo = SourceReader.ReadToEnd();

                var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + userType.UserTypeShortName + "&access_token=" + token;

                var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));

                var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";

                builder.HtmlBody = string.Format(templateInfo,
                    sysUserInfo.FullName,
                    trialInfo.ExperimentName,
                    trialInfo.ResearchProgramNo,
                    trialInfo.TrialCode,
                    sysUserInfo.UserName,
                    userType.UserTypeShortName,
                    sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl
                    );
            }

            messageToSend.Body = builder.ToMessageBody();

            await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);

            return sysUserInfo.Id;
        }



    }
}