using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using edu.jhu.Cas.Web;
using edu.jhu.Cas.Users;
using edu.jhu.Cas.Jobs;
using System.IO;
using net.ivoa.data;
using RestApi.Exceptions;
using System.Configuration;
using edu.jhu.Cas.Util;
using RestApi.Models;
using SciServer.Logging;
using System.Web;

namespace RestApi.Controllers
{
    public class UsersController : ApiController
    {
        [ExceptionHandle]
        public HttpResponseMessage Delete(string keystone_id)
        {
            Logger log = (HttpContext.Current.ApplicationInstance as MvcApplication).Log;

            IEnumerable<string> values;
            string userid = null;

            if (ControllerContext.Request.Headers.TryGetValues("X-Auth-Token", out values))
            {
                try
                {
                    string token = values.First();
                    var userAccess = Keystone.Authenticate(token);
                    userid = userAccess.User.Id;

                    if (!userAccess.User.Roles.Any(item => item.Name == "admin"))
                    {
                        AuthException ex = new AuthException("User must belong to the 'admin' role to perform this operation");
                        ex.Data["UserId"] = userid;
                        throw ex;
                    }
                }
                catch (AuthException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    AuthException ex2 = new AuthException("Authentication failed", ex);
                    ex2.Data["UserId"] = userid;
                    throw ex2;
                }

                try
                {
                    long admin_wsid = long.Parse(ConfigurationManager.AppSettings["ServiceID"]);

                    long? delete_wsid = Keystone.GetWebServicesId(keystone_id);
                    if (delete_wsid == null) throw new NotFoundException("CasJobs user with the given Keystone ID does not exist.");
                    CasUsers cu = new CasUsers();
                    cu.DeleteAccount(admin_wsid, delete_wsid.Value);
                }
                catch (NotFoundException) { throw; }
                catch (Exception ex)
                {
                    Exception ex2 = new Exception("Failed to delete user", ex);
                    ex2.Data["UserId"] = userid;
                    throw ex2;
                }

                log.SendMessage(log.CreateInfoMessage("User deleted: " + keystone_id));
                return ControllerContext.Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                throw new AuthException("User not authenticated");
            }
        }

        
        [ExceptionHandle]
        public HttpResponseMessage Get(string keystone_id)
        {
            Logger log = (HttpContext.Current.ApplicationInstance as MvcApplication).Log;

            IEnumerable<string> values;
            string userid = null;

            if (ControllerContext.Request.Headers.TryGetValues("X-Auth-Token", out values))
            {
                try
                {
                    string token = values.First();
                    var userAccess = Keystone.Authenticate(token);
                    userid = userAccess.User.Id;

                    if (!userAccess.User.Roles.Any(item => item.Name == "admin"))
                    {
                        AuthException ex = new AuthException("User must belong to the 'admin' role to perform this operation");
                        ex.Data["UserId"] = userid;
                        throw ex;
                    }
                }
                catch (AuthException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    AuthException ex2 = new AuthException("Authentication failed", ex);
                    ex2.Data["UserId"] = userid;
                    throw ex2;
                }


                try
                {
                    long admin_wsid = long.Parse(ConfigurationManager.AppSettings["ServiceID"]);

                    long? user_wsid = Keystone.GetWebServicesId(keystone_id);
                    if (user_wsid == null) throw new NotFoundException("CasJobs user with the given Keystone ID does not exist");

                    User[] users;
                    string query = 
                        "select [userid],[name],[email],[privileges],[gvisible],[webservicesid],[emaillevel],[timecreated],[server] as MyDBHost, MyDBName from users "+
                        "JOIN MyDBHosts ON Users.MyDBHost = MyDBHosts.MyDBHost where webservicesid = " + user_wsid.Value;
                    users = DataConverter.dataSet2User(SqlFactory.select(query));
                    if (users == null || users.Length == 0)
                    {
                        NotFoundException ex = new NotFoundException("User does not exist: " + keystone_id);
                        ex.Data["UserId"] = userid;
                        throw ex;
                    }
                    else
                    {
                        return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, UserInfo.FromUser(users[0]), "application/json");
                    }
                }
                catch (NotFoundException) { throw; }
                catch (Exception ex)
                {
                    Exception ex2 = new Exception("Failed to obtain user info", ex);
                    ex2.Data["UserId"] = userid;
                    throw ex2;
                }
            }
            else
            {
                throw new AuthException("User not authenticated");
            }
        }

        [ExceptionHandle]
        public HttpResponseMessage Put(string keystone_id, [FromBody]UserInfo user)
        {
            Logger log = (HttpContext.Current.ApplicationInstance as MvcApplication).Log;

            IEnumerable<string> values;
            string userid = null;

            if (ControllerContext.Request.Headers.TryGetValues("X-Auth-Token", out values))
            {
                try
                {
                    string token = values.First();
                    var userAccess = Keystone.Authenticate(token);
                    userid = userAccess.User.Id;

                    if (!userAccess.User.Roles.Any(item => item.Name == "admin"))
                    {
                        AuthException ex = new AuthException("User must belong to the 'admin' role to perform this operation");
                        ex.Data["UserId"] = userid;
                        throw ex;
                    }
                }
                catch (AuthException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    AuthException ex2 = new AuthException("Authentication failed", ex);
                    ex2.Data["UserId"] = userid;
                    throw ex2;
                }

                try
                {
                    long admin_wsid = long.Parse(ConfigurationManager.AppSettings["ServiceID"]);

                    CasUsers cu = new CasUsers();
                    long wsid = cu.CreateAccount(admin_wsid, user.UserId, user.FullName, user.Email, user.Password, null, 0, 1);
                    User newUser = cu.FindUser(edu.jhu.Cas.Util.ID.SERVICE_ID, "WEBSERVICESID=" + wsid)[0];
                    newUser.KeystoneID = keystone_id;
                    cu.UpdateAccount(wsid, newUser);

                    log.SendMessage(log.CreateInfoMessage("Account created for user: " + keystone_id));
                    return ControllerContext.Request.CreateResponse(HttpStatusCode.OK);
                }
                catch (Exception ex)
                {
                    Exception ex2 = new Exception("Failed to create account for user: " + keystone_id, ex);
                    ex2.Data["UserId"] = userid;
                    throw ex2;
                }
            }
            else
            {
                throw new AuthException("User not authenticated");
            }
        }
    }
}
