using System;
using System.Data.SqlTypes;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using MileageTraker.Web.Attributes;
using MileageTraker.Web.DAL;
using MileageTraker.Web.Email;
using MileageTraker.Web.Utility;
using MileageTraker.Web.ViewModels;
using MileageTraker.Web.ViewModels.User;

namespace MileageTraker.Web.Controllers
{
	[Authorize(Roles = "Administrator, Developer")]
    public class UserController : ControllerBase
    {
        public ActionResult Index()
        {
	        var users =
				DataService
				.GetUsers()
				.ToList()
				.OrderBy(u => u.Username);

	        return View(users);
        }

		[ActionLog]
		public ActionResult Export()
		{
			var users = DataService.GetUsers();
			var userViewModels =
				users
					.ToList()
					.OrderBy(u => u.Username)
					.Select(log => new ExportUserViewModel(log));

			var name = string.Format(
				"MileageTrakerUsers_{0:MM-dd-yyyy}", DateTime.Today);

			var export = ExcelWriter.WriteXls(userViewModels, name, name);
			return File(export, "application/ms-excel", name + ".xls");
		}


		public ActionResult Details(Guid id)
        {
	        var user = Membership.GetUser(id);
            if (user == null)
            {
                return HttpNotFound();
            }
			return View(DataService.GetUser(id));
        }

		public ActionResult DetailsFullName(string employeeName)
		{
			var user = DataService.FindUserByFullName(employeeName);
            if (user == null)
            {
				user = DataService.FindUserByUsername(employeeName);
	            if (user == null)
	            {
		            TempData["StatusMessage"] = "User " + employeeName + " not found";
		            return RedirectToAction("Index");
	            }
            }
			return View("Details", user);
		}

		public JsonResult UsernameAvailable(string username)
		{
			var user = DataService.FindUserByUsername(username);
			return Json(user == null, JsonRequestBehavior.AllowGet);
		}

		public JsonResult FullNameAvailable(string fullname)
		{
			var user = DataService.FindUserByFullName(fullname);
			return Json(user == null, JsonRequestBehavior.AllowGet);
		}

		public JsonResult ExistsByFullName(string userFullName)
		{
			var user = DataService.FindUserByFullName(userFullName);
			return Json(user != null, JsonRequestBehavior.AllowGet);
		}

		public ActionResult Create()
        {
	        var vm = new CreateUserViewModel
		        {
					Roles = new CheckBoxViewModel{
						Available = Roles.GetAllRoles(),
						Selected = new []{"Driver"} // default driver
					}
		        };

	        return View(vm);
        }

		[ActionLog]
		[HttpPost]
		public ActionResult Create(CreateUserViewModel viewModel)
        {
            if (ModelState.IsValid)
            {
	            MembershipCreateStatus membershipCreateStatus;
	            var membershipUser = 
					Membership.CreateUser(
						viewModel.Username,
						CodeFirstMembershipProvider.UninitializedPassword, 
						viewModel.Email,
						null,
						null,
						true,
						out membershipCreateStatus);

	            if (membershipUser == null)
	            {
		            ModelState.AddModelError("", ErrorCodeToString(membershipCreateStatus));
		            viewModel.Roles.Available = Roles.GetAllRoles();
					return View(viewModel);
	            }

				if (viewModel.Roles != null)
				{
					Roles.AddUserToRoles(
						membershipUser.UserName,
						viewModel.Roles.Selected);
				}

	            var user = DataService.GetUser((Guid) membershipUser.ProviderUserKey);
	            user.FullName = viewModel.FullName;
				DataService.UpdateUserPersonalInfo(user);

	            if (viewModel.SetPassword)
	            {
					TempData["StatusMessage"] = "User " + user.Username + " created";
					return RedirectToAction("SetPassword", new { id = user.UserId });
	            }

	            var email = new EmailNotificationService();
				var resetPasswordUrl = ResetPassword(user);
				email.SendInitializePassword(user, resetPasswordUrl);

				TempData["StatusMessage"] = "User " + user.Username + " created, invitation sent to " + user.Email;
				return RedirectToAction("Index");
            }

			viewModel.Roles.Available = Roles.GetAllRoles();
			return View(viewModel);
        }

		[HttpGet]
		public JsonResult SendInvite(Guid userId)
		{
			var user = DataService.GetUser(userId);
			var resetPasswordUrl = ResetPassword(user);
			var email = new EmailNotificationService();
			email.SendInitializePassword(user, resetPasswordUrl);
			return Json(true, JsonRequestBehavior.AllowGet);
		}

		[HttpGet]
		public ActionResult SendResetPassword(Guid userId)
		{
			var user = DataService.GetUser(userId);
			var resetPasswordUrl = ResetPassword(user);
			var email = new EmailNotificationService();
			email.SendResetPassword(user, resetPasswordUrl);
			TempData["StatusMessage"] = "Reset password sent to User " + user.Username + " at " + user.Email;
			return RedirectToAction("Details", new { id = userId}); 
		}

		[Authorize(Roles = "Developer")]
		public ActionResult InviteUninitialized()
		{
			var uninitializedUsers =
				(from user in DataService.GetUsers()
				 where user.LastPasswordChangedDate == SqlDateTime.MinValue.Value
				       && user.LastActivityDate == SqlDateTime.MinValue.Value
				       && user.IsApproved
				 orderby user.Username
				 select user).ToList();

			return View(uninitializedUsers);
		}

		public ActionResult Edit(Guid id)
        {
            var user = DataService.GetUser(id);
            if (user == null)
            {
                return HttpNotFound();
            }

			var vm = new EditUserViewModel(user)
			{
				Roles = new CheckBoxViewModel
				{
					Selected = Roles.GetRolesForUser(user.Username),
					Available = Roles.GetAllRoles()
				}
			};

			return View(vm);
        }

		[ActionLog]
		[HttpPost]
		public ActionResult Edit(EditUserViewModel viewModel)
		{
			if (ModelState.IsValid)
			{
				var user = DataService.GetUser(viewModel.UserId);
				viewModel.UpdateUser(user);
				DataService.UpdateUserPersonalInfo(user);

				Roles.RemoveUserFromRoles(user.Username, Roles.GetAllRoles());
				if (viewModel.Roles != null)
				{
					Roles.AddUserToRoles(
						user.Username,
						viewModel.Roles.Selected);
				}

				TempData["StatusMessage"] = "Changes saved for " + user.Username;
				return RedirectToAction("Details", new { id = viewModel.UserId});
			}
			return View(viewModel);
		}

		public ActionResult SetPassword(Guid id)
		{
			var user = Membership.GetUser(id);
			if (user == null)
				return HttpNotFound();

			var viewModel = new SetPasswordViewModel {UserId = id, Username = user.UserName};
			return View(viewModel);
		}

		[HttpPost]
		public ActionResult SetPassword(SetPasswordViewModel viewModel)
		{
			if (ModelState.IsValid)
			{
				DataService.UpdateUserPassword(viewModel.UserId, viewModel.NewPassword);
				TempData["StatusMessage"] = "Password set for " + viewModel.Username;
				return RedirectToAction("Details", new { id = viewModel.UserId});
			}

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

		[ActionLog]
		public ActionResult DisableUser(Guid id)
		{
			var user = DataService.GetUser(id);
			if (user == null)
			{
				return HttpNotFound();
			}
			if (user.Username == User.Identity.Name)
			{
				TempData["StatusMessage"] = "Cannot disable yourself!";
				TempData["StatusMessage-Type"] = "alert-error";
			}
			else
			{
				user.IsApproved = false;
				DataService.UpdateUser(user);

				TempData["StatusMessage"] = user.Username + " disabled";
			}

			if (Request.UrlReferrer != null)
				return Redirect(Request.UrlReferrer.AbsolutePath);
			return RedirectToAction("Index");
		}

		[ActionLog]
		public ActionResult EnableUser(Guid id)
		{
			var user = DataService.GetUser(id);
			if (user == null)
			{
				return HttpNotFound();
			}
			user.IsApproved = true;
			DataService.UpdateUser(user);

			TempData["StatusMessage"] = user.Username + " enabled";

			if (Request.UrlReferrer != null)
				return Redirect(Request.UrlReferrer.AbsolutePath);
			return RedirectToAction("Index");
		}

		[ActionLog]
		public ActionResult UnlockUser(Guid id)
		{
			var user = DataService.GetUser(id);
			if (user == null)
			{
				return HttpNotFound();
			}
			user.IsLockedOut = false;
			user.PasswordFailuresSinceLastSuccess = 0;
			DataService.UpdateUser(user);

			TempData["StatusMessage"] = user.Username + " unlocked";

			if (Request.UrlReferrer != null)
				return Redirect(Request.UrlReferrer.AbsolutePath);
			return RedirectToAction("Index");
		}

		[Authorize(Roles = "Driver, Administrator, Developer")]
		public JsonResult Autocomplete(string term)
		{
			var employees = DataService.GetUserFullNamesAutocomplete(term);
			return Json(employees, JsonRequestBehavior.AllowGet);
		}

		private static string ErrorCodeToString(MembershipCreateStatus createStatus)
		{
			// See http://go.microsoft.com/fwlink/?LinkID=177550 for
			// a full list of status codes.
			switch (createStatus)
			{
				case MembershipCreateStatus.DuplicateUserName:
					return "User name already exists. Please enter a different user name.";

				case MembershipCreateStatus.DuplicateEmail:
					return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

				case MembershipCreateStatus.InvalidPassword:
					return "The password provided is invalid. Please enter a valid password value.";

				case MembershipCreateStatus.InvalidEmail:
					return "The e-mail address provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidAnswer:
					return "The password retrieval answer provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidQuestion:
					return "The password retrieval question provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidUserName:
					return "The user name provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.ProviderError:
					return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

				case MembershipCreateStatus.UserRejected:
					return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

				default:
					return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
			}
		}
    }
}