using System;
using System.Web.Mvc;
using System.Web.Security;
using MileageTraker.Web.Attributes;
using MileageTraker.Web.DAL;
using MileageTraker.Web.Email;
using MileageTraker.Web.ViewModels.Account;

namespace MileageTraker.Web.Controllers
{
	[Authorize]
    public class AccountController : ControllerBase
    {
		[AllowAnonymous]
		public ActionResult Login(string returnUrl, string username)
		{
			ViewBag.ReturnUrl = returnUrl;
			return View(new LoginViewModel{Username = username});
		}

		[HttpPost]
		[AllowAnonymous]
		[ValidateAntiForgeryToken]
		public ActionResult Login(LoginViewModel model, string returnUrl)
		{
			if (ModelState.IsValid)
			{
				try
				{
					var success = Membership.ValidateUser(model.Username, model.Password);
					if (success)
					{
						FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
						TempData["StatusMessage"] = "Logged in as " + model.Username;
						return RedirectToLocal(returnUrl);
					}
					ModelState.AddModelError("", "The user name or password provided is incorrect.");
				}
				catch (UserAccountDisabledException)
				{
					ModelState.AddModelError("", "Account is disabled for " + model.Username + ".");
				}
				catch (UserLockedOutException)
				{
					ModelState.AddModelError("",
					                         "Too many failed password attempts for " +
					                         model.Username + ". Account is locked. " +
					                         @"Use 'Forgot Password' or contact " +
					                         "administrator to unlock.");
				}
				catch (UninitializedAccountException)
				{
					ModelState.AddModelError("",
						 "Account for " +
						 model.Username + " has not been initialized. " +
						 @"Please check your email for initialization instructions.");
				}
			}

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

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult LogOff()
		{
			TempData["StatusMessage"] = User.Identity.Name + " logged off";

			FormsAuthentication.SignOut();

			return RedirectToAction("Index", "CreateLog");
		}
		
		public ActionResult Manage(ManageMessageId? message)
		{
			ViewBag.StatusMessage =
				message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
				: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
				: null;
			ViewBag.ReturnUrl = Url.Action("Manage");

			var user = DataService.FindUserByUsername(User.Identity.Name);
			var viewModel = new ChangePasswordViewModel(user);

			return View(viewModel);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		[ActionLog]
		public ActionResult Manage(ChangePasswordViewModel model)
		{
			ViewBag.ReturnUrl = Url.Action("Manage");

			var membershipUser = Membership.GetUser(User.Identity.Name, true);
			//var user = DataService.FindUserByUsername(User.Identity.Name);
			//model.SetProperties(user);

			if (ModelState.IsValid)
			{
				// ChangePassword will throw an exception rather than return false in certain failure scenarios.
				bool changePasswordSucceeded;
				try
				{
					changePasswordSucceeded = membershipUser.ChangePassword(model.OldPassword, model.NewPassword);
				}
				catch (Exception)
				{
					changePasswordSucceeded = false;
				}

				if (changePasswordSucceeded)
				{
					TempData["StatusMessage"] = "Your password has been changed.";
					return RedirectToAction("Manage");
				}
				ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
			}

			// If we got this far, something failed, redisplay form
			return View(model);
		}
		
		private ActionResult RedirectToLocal(string returnUrl)
		{
			if (Url.IsLocalUrl(returnUrl))
			{
				return Redirect(returnUrl);
			}
			return RedirectToAction("Index", "Log");
		}

		public enum ManageMessageId
		{
			ChangePasswordSuccess,
			SetPasswordSuccess,
		}

		#region Reset Password

		/// <summary>
		/// View the Reset Password form
		/// </summary>
		[AllowAnonymous]
		[HttpGet]
		public ViewResult ResetPassword(string username)
		{
			return View(new ResetPasswordViewModel{Username = username});
		}

		/// <summary>
		/// Begins the Reset Password process
		/// </summary>
		[AllowAnonymous]
		[HttpPost]
		[ValidateAntiForgeryToken]
		[ActionLog]
		public ActionResult ResetPassword(ResetPasswordViewModel viewModel)
		{
			var user = DataService.FindUserByUsername(viewModel.Username);
			if (user != null && user.IsApproved && Request.Url != null)
			{
				var email = new EmailNotificationService();
				var resetPasswordUrl = ResetPassword(user);
				email.SendResetPassword(user, resetPasswordUrl);
				TempData["StatusMessage"] = "Please check your email - we have sent a request for you to reset the password.";
			}
			else if (user == null)
			{
				TempData["StatusMessage"] = "Could not find username " + viewModel.Username + ".";
				TempData["StatusMessage-Type"] = "alert-error";
				return RedirectToAction("ResetPassword");
			}
			else if (!user.IsApproved)
			{
				TempData["StatusMessage"] = "Account is disabled for " + viewModel.Username + ".";
				TempData["StatusMessage-Type"] = "alert-error";
			}
			
			// even when if not successful, let the user think they're getting a cookie
			return RedirectToAction("Login");
		}

		/// <summary>
		/// Action users are sent to when they reset their password.
		/// </summary>
		[AllowAnonymous]
		[HttpGet]
		public ActionResult NewPassword(Guid userId, string passwordResetToken)
		{
			var user = DataService.GetUser(userId);
			if (user != null && user.IsApproved && 
				user.PasswordResetToken == passwordResetToken)
			{
				var newPasswordViewModel
					= new NewPasswordViewModel
					{
						UserId = user.UserId,
						Username = user.Username,
						PasswordResetToken = passwordResetToken
					};
				return View(newPasswordViewModel);
			}

			return HttpNotFound();
		}

		/// <summary>
		/// Set a new password.
		/// </summary>
		/// <param name="viewModel">The view model.</param>
		[AllowAnonymous]
		[HttpPost]
		[ValidateAntiForgeryToken]
		[ActionLog]
		public ActionResult NewPassword(NewPasswordViewModel viewModel)
		{
			if (ModelState.IsValid)
			{
				var user = DataService.GetUser(viewModel.UserId);
				if (user != null && user.IsApproved &&
					user.PasswordResetToken == viewModel.PasswordResetToken)
				{
					DataService.UpdateUserPassword(viewModel.UserId, viewModel.NewPassword);
					var success = Membership.ValidateUser(user.Username, viewModel.NewPassword);
					if (success)
					{
						FormsAuthentication.SetAuthCookie(viewModel.Username, false);
						TempData["StatusMessage"] = "Password set for " + viewModel.Username + ", logged in";
						return RedirectToAction("Index", "CreateLog");
					}
				}
			}

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

		#endregion
    }
}
