using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;
using Sevomin.Models;
using Sevomin.Models.Helpers;
using Sevomin.Models.Repositories;
using System;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Linq;

namespace Sevomin.WebFrontend.Controllers
{
    public class AccountController : BaseController
    {                
        public AccountController()
            : this(new SevominUserManager(new UserStore<User>(SevominDbContext.Current)))
        {
        }

        public AccountController(SevominUserManager userManager)
        {
            UserManager = userManager;
        }

        public SevominUserManager UserManager { get; private set; }        

        private IAuthenticationManager AuthenticationManager
        {
            get
            {
                return HttpContext.GetOwinContext().Authentication;
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Signup(SignupViewModel model)
        {
            User user;
            if (model.IsAvalin)
            {
                user = new Avalin(model.Email, model.DisplayName);
                user.SignUpDate = DateTime.UtcNow;
            }
            else
            {                
                user = new Dovomin(model.Email, model.DisplayName, string.Empty);
                user.SignUpDate = DateTime.UtcNow;
            }
            user.DisplayName = model.DisplayName;
            user.Email = model.Email;
            user.ConfirmationCode = Sevomin.Models.User.GetConfirmationCode();
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(SevominDbContext.Current));
                if (!(await roleManager.RoleExistsAsync("Avalin")))
                    await roleManager.CreateAsync(new IdentityRole("Avalin"));

                if (!(await roleManager.RoleExistsAsync("Dovomin")))
                    await roleManager.CreateAsync(new IdentityRole("Dovomin"));

                //Todo: Check this
                UserManager.UserValidator = new UserValidator<User>(UserManager);

                if (user is Avalin)
                    await UserManager.AddToRoleAsync(user.Id, "Avalin");
                else if(user is Dovomin)
                    await UserManager.AddToRoleAsync(user.Id, "Dovomin");

#if !DEBUG
                SevominEmailer emailer = new SevominEmailer();
                emailer.EmailType = EmailType.EmailConfirmation;
                emailer.Parameters.Add("display-name", user.DisplayName);
                emailer.Parameters.Add("confirmation-code", user.ConfirmationCode);
                await emailer.SendAsync(user.Email, "تایید عضویت در سومین", true);
#endif

                await SignInAsync(user, isPersistent: false);
                return RedirectToAction("MyProfile", "Account");
            }
            else
            {
                AddErrors(result);
            }

            return View("Intro", model);
        }
        
        public async Task<ActionResult> CheckUsername(string Email)
        {
            bool result = (await UserManager.FindByNameAsync(Email)) == null;
            if(result)
                return Json(true, JsonRequestBehavior.AllowGet);

            return Json("این ایمیل قبلا در سایت استفاده شده. کلمه عبور خود را فراموش کرده اید؟", JsonRequestBehavior.AllowGet);
        }

        public ActionResult ConfirmEmail(string code)
        {
            var user = UserRepository.Current.FindWithConfirmationCode(code);
            if (user == null)
                return HttpNotFound();

            if (Request.IsAuthenticated && User.Identity.Name.ToLower() != user.UserName.ToLower())
            {
                ViewBag.Result = new PostResultViewModel(false, 
                    string.Format("شما با نام کاربری {0} در سایت وارد شده اید. نمی توانید حساب کاربری {1} را تایید نمایید.", 
                    User.Identity.Name, user.UserName));
                return View();
            }

            user.EmailConfirmed = true;
            user.ConfirmationCode = string.Empty;

            UserRepository.Current.Save();
            UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);            
            ViewBag.Result = new PostResultViewModel(true, string.Format("حساب کاربری شما با موفقیت تایید شد. لطفا {0} سایت شوید", 
                HtmlHelper.GenerateLink
                (this.ControllerContext.RequestContext, System.Web.Routing.RouteTable.Routes, "وارد", "Login", "Login", "Account", null, null)));
            return View();
        }

        public ActionResult Login(string returnUrl)
        {
            if(Request.IsAuthenticated)
                return RedirectToAction("Index", "Home");

            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindAsync(model.Username, model.Password);
                if (user != null)
                {
                    await SignInAsync(user, true);
                    return RedirectToLocal(returnUrl);
                }
                else
                {
                    ModelState.AddModelError("", "نام کاربری و یا کلمه عبور وارد شده صحیح نمی باشد.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        public ActionResult Logout()
        {
            AuthenticationManager.SignOut();
            return RedirectToAction("Index", "Home");
        }
        
        public ActionResult Forgot()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Forgot(ForgotPasswordViewModel model)
        {
            var user = UserRepository.Current.Find(model.Email);
            if (user == null)
            {
                ViewBag.Result = new PostResultViewModel(false, "کاربری با این آدرس ایمیل یافت نشد. لطفا دوباره تلاش کنید.");
                return View();
            }
            user.ConfirmationCode = Sevomin.Models.User.GetConfirmationCode();
            UserRepository.Current.Save();

#if !DEBUG
            SevominEmailer emailer = new SevominEmailer();
            emailer.EmailType = EmailType.PasswordReset;
            emailer.Parameters.Add("display-name", user.DisplayName);
            emailer.Parameters.Add("reset-code", user.ConfirmationCode);
            await emailer.SendAsync(user.Email, "بازنشانی رمز عبور در سومین", true);
#endif

            ViewBag.Result = new PostResultViewModel(true, "آدرس بازنشانی رمز عبور برای شما ارسال شد.");
            return View();
        }
        
        public ActionResult ResetPassword(string code)
        {
            var user = UserRepository.Current.FindWithConfirmationCode(code);
            if (user == null)
                return HttpNotFound();

            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> ResetPassword(string code, ResetPasswordViewModel model)
        {
            var user = UserRepository.Current.FindWithConfirmationCode(code);
            if (user == null)
                return HttpNotFound();

            await UserManager.RemovePasswordAsync(user.Id);
            await UserManager.AddPasswordAsync(user.Id, model.Password);
            user.ConfirmationCode = string.Empty;
            UserRepository.Current.Save();

            ViewBag.Result = new PostResultViewModel(true, "رمز عبور شما با موفقیت بازنشانی شد.");

            return View();
        }

        [Authorize]        
        public ActionResult ChangePassword()
        {
            return View();
        }

        [Authorize]
        [HttpPost]
        public async Task<ActionResult> ChangePassword(ChangePasswordViewModel model)
        {
            var user = await UserManager.FindAsync(User.Identity.Name, model.Password);
            if (user != null)
            {
                await UserManager.RemovePasswordAsync(user.Id);
                await UserManager.AddPasswordAsync(user.Id, model.NewPassword);
                UserRepository.Current.Save();

                ViewBag.Result = new PostResultViewModel(true, "رمز عبور شما با موفقیت به روز شد.");
                return View();
            }
            else
            {
                ViewBag.Result = new PostResultViewModel(false, "رمز عبور فعلی وارد شده با اطلاعات ما مطابقت ندارد. لطفا دوباره تلاش کنید.");
                return View();
            }
        }
			

        [Authorize]
        public async Task<ActionResult> MyProfile(bool? success)
        {
            if (success.HasValue)
            {
                ViewBag.Result = new PostResultViewModel(success.Value, success.Value ? "پروفایل شما با موفقیت ویرایش شد." : "در ویرایش پروفایل شما خطایی رخ داده.");
            }

            User u = await UserManager.FindByNameAsync(User.Identity.Name);
            if (u is Avalin)
            {
                return View("ProfileAvalin", new AvalinViewModel(u as Avalin));
            }
            else
            {
                Dovomin dovomin = (Dovomin)u;
                DovominViewModel dvm = new DovominViewModel(dovomin);
                return View("ProfileDovomin", dvm);
            }
        }

        [Authorize]
        [HttpPost]
        public async Task<ActionResult> ProfileDovomin(string JalaliBirthDate, string FirstName,
            string LastName, string ContactPersonEMail, bool IsFullTime,
            bool IsPartTime, string Description, HttpPostedFileBase EnglishResume, HttpPostedFileBase PersianResume, FormCollection form)
        {
            User u = await UserManager.FindByNameAsync(User.Identity.Name);
            if (u == null || !(u is Dovomin))
                throw new InvalidOperationException("نوع کاربر صحیح نیست");

            try
            {
                Dovomin dovomin = (Dovomin)u;
                dovomin.BirthDate = DateAssist.ValidateAndSetToMiladi(JalaliBirthDate);
                dovomin.Description = Description;
                dovomin.FirstName = FirstName;
                dovomin.LastName = LastName;
                dovomin.IsFulltime = IsFullTime;
                dovomin.IsPartTime = IsPartTime;

                ParameterRepository.Current.AddParametersToDovomin(dovomin);
                foreach (var jp in dovomin.DovominParameters)
                {
                    string value = form[string.Format("value-{0}", jp.Parameter.Id)];
                    jp.SetValue(value);
                }

                if (EnglishResume != null)
                {
                    dovomin.EnglishResume = string.Format("{0}-resume-en{2}", User.Identity.Name, "", System.IO.Path.GetExtension(EnglishResume.FileName));
                    EnglishResume.SaveAs(System.IO.Path.Combine(Server.MapPath("~/App_Data/resumes"), dovomin.EnglishResume));
                }
                if (PersianResume != null)
                {
                    dovomin.PersianResume = string.Format("{0}-resume-fa{2}", User.Identity.Name, "", System.IO.Path.GetExtension(PersianResume.FileName));
                    PersianResume.SaveAs(System.IO.Path.Combine(Server.MapPath("~/App_Data/resumes"), dovomin.PersianResume));
                }

                SevominDbContext.Current.SaveChanges();

                return RedirectToAction("MyProfile", new { success = true });
            }
            catch (Exception)
            {
                throw;
            }
        }

        [Authorize]
        [HttpPost]
        public async Task<ActionResult> ProfileAvalin(string CompanyName, string NationalId, string RegisterId,
            string Address, string CompanyPhoneNumber, string EMail)
        {
            User u = await UserManager.FindByNameAsync(User.Identity.Name);
            try
            {
                if (u == null || !(u is Avalin))
                    throw new InvalidOperationException("نوع کاربر صحیح نیست");
                Avalin avalin = (Avalin)u;
                avalin.CompanyName = CompanyName;
                avalin.NationalId = NationalId;
                avalin.RegisterId = RegisterId;
                avalin.Address = Address;
                avalin.CompanyPhoneNumber = CompanyPhoneNumber;
                avalin.Email = EMail;

                SevominDbContext.Current.SaveChanges();

                return RedirectToAction("MyProfile", new { success = true });
            }
            catch (Exception)
            {

                throw;
            }
        }

        public async Task<ActionResult> Dovomin(string userId)
        {
            User user = await UserManager.FindByIdAsync(userId);

            if ((user as Dovomin) == null)
                return HttpNotFound();

            if (User.IsInRole("Dovomin"))
            {
                if (userId != user.Id)
                {
                    return HttpNotFound();
                }
                else { }
            }
            else if (User.IsInRole("Avalin"))
            {
                Avalin avalin = (await UserManager.FindByNameAsync(User.Identity.Name)) as Avalin;
                bool showIt = avalin.Jobs.Any(j => {
                    bool ret = j.Applications.Any(c => c.DovominId == userId);
                    return ret;
                });
                if (!showIt)
                    return HttpNotFound();
            }

            return View(new DovominViewModel(user as Dovomin));
        }

        private async Task SignInAsync(User user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }

        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        private void AddErrors(IdentityResult result)
        {
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
        }        
    }
}