using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Security;
using AutoMapper;
using Qusion.Cms.Classifications.Core;
using Qusion.Cms.Users.Core;
using Qusion.Cms.Users.Domain;
using Qusion.Cms.Web.Http;
using Qusion.WebApp.Areas.Qusion.Mailers.Account;
using Qusion.WebApp.Areas.Qusion.Models.Users;
using WebMatrix.WebData;

namespace Qusion.WebApp.Areas.Qusion.Controllers.Api
{
    [Authorize(Roles = "Administrator,Administrators")]
    public class UserController : ApiController
    {
        private readonly LabelService _labelService;

        private readonly UserService _userService;

        public UserController(UserService userService, LabelService labelService)
        {
            _userService = userService;
            _labelService = labelService;
        }

        [HttpGet]
        public HttpResponseMessage Current()
        {
            User user = _userService.Get(User.Identity.Name);
            UserModel model = Mapper.Map<User, UserModel>(user);
            return Request.CreateResponse(HttpStatusCode.OK, model);
        }

        [HttpGet]
        public PageResult<UserListModel> Query([FromUri] UserQueryInput input)
        {
            UserQuery query = Mapper.Map<UserQueryInput, UserQuery>(input) ?? UserQuery.Default;

            IEnumerable<User> users = _userService.Search(query);
            IList<UserListModel> model = Mapper.Map<IList<User>, IList<UserListModel>>(users.ToList());

            return new PageResult<UserListModel>
                       {
                           Items = model,
                           Count = query.Paging.TotalCount
                       };
        }

        [HttpGet]
        public UserModel Get(Guid id)
        {
            User user = _userService.GetById(id);
            return Mapper.Map<User, UserModel>(user);
        }

        /// <summary>
        ///   Create new user.
        /// </summary>
        /// <param name="model"> </param>
        /// <returns> </returns>
        [HttpPost]
        public HttpResponseMessage Create(UserCreateInput model)
        {
            var errors = new Dictionary<string, string[]>();

            if (WebSecurity.UserExists(model.Email))
                errors.Add("model.Email", new[] {"users.EmailExist"});

            if (errors.Count == 0)
            {
                var user = new User
                               {
                                   FirstName = model.FirstName,
                                   LastName = model.LastName,
                                   UserName = model.Email,
                                   Roles = string.Join(",", model.Roles)
                               };
                if (model.Labels != null)
                {
                    user.Labels.Clear();
                    foreach (string labelId in model.Labels)
                    {
                        user.Labels.Add(_labelService.GetById(new Guid(labelId)));
                    }
                }

                _userService.Save(user);

                string token = WebSecurity.CreateAccount(user.UserName, model.Password, true);

                Roles.AddUserToRoles(user.UserName, model.Roles);

                var mail = new CreateNewAccount
                               {
                                   Email = model.Email,
                                   UserName = model.Email,
                                   Password = model.Password,
                                   Token = token
                               };
                // send password reset token
                new AccountMailer().CreateUser(mail).Send();
                return Request.CreateResponse(HttpStatusCode.OK);
            }

            return Request.CreateResponse(HttpStatusCode.OK, new {Error = true, Errors = errors});
        }

        /// <summary>
        /// Change user password.
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public HttpResponseMessage ChangePassword(ChangePasswordInput password)
        {
            var errors = new Dictionary<string, string[]>();

            if (errors.Count == 0)
            {
                User user = _userService.GetById(password.ID);

                if (user != null)
                {
                    MembershipUser muser = Membership.GetUser(user.UserName);
                    if (muser != null)
                    {
                        bool isChnaged = muser.ChangePassword(password.CurrentPass, password.NewPass);

                        if (isChnaged)
                        {
                            var mail = new ChangePasswordMailerModel
                                           {
                                               Email = user.Email,
                                               UserName = user.UserName,
                                               Password = password.NewPass
                                           };

                            new AccountMailer().ChangePassword(mail).Send();

                            return Request.CreateResponse(HttpStatusCode.OK);
                        }

                        errors.Add("password.CurrentPass", new[] {"users.ivnalidCurrentPass"});
                    }

                    return Request.CreateResponse(HttpStatusCode.OK, new {Errors = errors});
                }
            }
            return Request.CreateResponse(HttpStatusCode.OK, new {Errors = errors});
        }


        [HttpGet]
        public UserModel GetEdit(Guid id)
        {
            User user = _userService.GetByIdForEditing(id);
            return Mapper.Map<User, UserModel>(user);
        }

        [HttpPost]
        public HttpResponseMessage Edit(UserEditInput model)
        {
            User user = _userService.GetByIdForEditing(model.ID);

            var errors = new Dictionary<string, string[]>();
            if (WebSecurity.UserExists(model.Email) && user.Email != model.Email)
            {
                errors.Add("model.Email", new[] {"users.EmailExist"});
            }
            if (errors.Count == 0)
            {
                string[] roles = Roles.GetRolesForUser(user.UserName);
                Mapper.Map(model, user);

                if (model.Labels != null)
                {
                    user.Labels.Clear();
                    foreach (string labelId in model.Labels)
                    {
                        user.Labels.Add(_labelService.GetById(new Guid(labelId)));
                    }
                }
               

                if (model.Roles != null)
                {
                    if (roles.Any())
                        Roles.RemoveUserFromRoles(user.UserName, roles);
                    if (model.Roles.Any())
                        Roles.AddUserToRoles(user.UserName, model.Roles);

                    user.Roles = string.Join(",", model.Roles);
                }

                _userService.Save(user);
                return Request.CreateResponse(HttpStatusCode.OK);
            }

            return Request.CreateResponse(HttpStatusCode.OK, new {Error = true, Errors = errors});
        }

        [HttpGet]
        public HttpResponseMessage Settings()
        {
            UserSettings.GeneralSection settings = _userService.Settings.General;
            UserSettingsModel model = Mapper.Map<UserSettings.GeneralSection, UserSettingsModel>(settings);
            return Request.CreateResponse(HttpStatusCode.OK, model);
        }

        [HttpPost]
        public HttpResponseMessage Settings(UserSettingsInput model)
        {
            UserSettings.GeneralSection settings = _userService.Settings.General;
            Mapper.Map(model, settings);
            ;
            _userService.Settings.Save();
            UserSettingsModel response = Mapper.Map<UserSettings.GeneralSection, UserSettingsModel>(settings);
            return Request.CreateResponse(HttpStatusCode.OK, response);
        }

        /// <summary>
        ///   Deactive user.
        /// </summary>
        /// <param name="id">User id.</param>
        /// <returns> </returns>
        [HttpGet]
        public HttpResponseMessage Delete(Guid id)
        {
            User user = _userService.GetById(id);
            if (user != null)
            {
                user.Deactived = true;
                _userService.Save(user);
                return Request.CreateResponse(HttpStatusCode.OK, new {Error = false});
            }
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }

        /// <summary>
        ///   Set user parameter Locked to true or false. Inidcates whether the user can access the system.
        /// </summary>
        /// <param name="id"> User id. </param>
        /// <returns> Http status code 200 (Ok) or 404 (NotFound) </returns>
        [HttpGet]
        public HttpResponseMessage Status(Guid id)
        {
            User user = _userService.GetById(id);
            if (user != null)
            {
                user.Locked = user.Locked == false;
                _userService.Save(user);
                return Request.CreateResponse(HttpStatusCode.OK, new {user.Locked});
            }
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }

        /// <summary>
        ///   Get all roles.
        /// </summary>
        /// <returns> </returns>
        public HttpResponseMessage GetRoles()
        {
            var roles = Roles.GetAllRoles().Select(x => new {Value = x, Name = x});
            return Request.CreateResponse(HttpStatusCode.OK, roles);
        }
    }
}