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 System.Net.Http.Headers;
using edu.jhu.Cas.Util;
using System.Web;
using edu.jhu.Cas.Jobs;
using RestApi.Models;
using RestApi.Exceptions;
using SciServer.Logging;
using Newtonsoft.Json;

namespace RestApi.Controllers
{
    public class QueryController : ApiController
    {
        [ExceptionHandle]
        public HttpResponseMessage Post(string context_id, [FromBody]QuickRequest req)
        {
            Logger log = (HttpContext.Current.ApplicationInstance as MvcApplication).Log;

            IEnumerable<string> values;
            long? wsid;
            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") && ControllerContext.Request.Headers.TryGetValues("X-Owner", out values))
                    {
                        userid = values.First();
                        wsid = Keystone.GetWebServicesId(values.First());
                    }
                    else
                    {
                        wsid = Keystone.GetWebServicesId(userAccess.User.Id);
                    }
                    if (wsid == null) throw new Exception("CasJobs user with the given Keystone ID does not exist");
                }
                catch (Exception ex)
                {
                    AuthException ex2 = new AuthException("Authentication failed", ex);
                    ex2.Data["UserId"] = userid;
                    log.SendMessage(log.CreateErrorMessage(ex2));
                    throw ex2;
                }
            }
            else
            {
                //throw new AuthException("User not authenticated");
                wsid = 0; // anonymous user
                userid = "";
                /*
                if ("mydb".Equals(context_id, StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new Exception("MyDB context is not allowed for anonymous user");
                }
                */
            }

            HttpResponseMessage response = Request.CreateResponse();

            try
            {
                Message msg = log.CreateCustomMessage("UNDEFINED", JsonConvert.SerializeObject(req));
                msg.UserId = userid;
                log.SendMessage(msg);

                string query = req.Query;
                string taskName = req.TaskName;

                CasJobs cj = new CasJobs();
                int actualEstimate = 1;
                Server[] servers = cj.getVirtualHostAndMyDBServer(wsid.Value, context_id, actualEstimate);
                string mQuery = cj.GetModifiedQuery(wsid.Value, query, context_id, actualEstimate, out actualEstimate);
                long jobNum = CasJobs.CreateJob(wsid.Value, query, mQuery, context_id, taskName, actualEstimate, 0);
                ReaderObject qObject = null;
                edu.jhu.Cas.Util.Job job = null;
                try
                {
                    job = cj.FindJob(wsid.Value, "jobid = " + jobNum)[0];
                    string ip = "0.0.0.0";
                    try { ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; }
                    catch { }
                    qObject = new ReaderObject(job, servers[1], servers[0], true, ip);
                    if (job.TaskName.StartsWith(SYSTEM.TAB_IMPORT_MESSAGE))
                    {
                        string ctab = job.Query.Substring(SYSTEM.TAB_IMPORT_QRY_PREF.Length);
                        ctab = ctab.Trim(new char[] { ' ', '\'' });
                        job.Created_Table = ctab;
                    }
                }
                catch (Exception e)
                {
                    ToughJobs.FailJob(0, wsid.Value, jobNum, e.Message + "\n" + e.StackTrace, ""); //really not expecting failures here, so include the stacktrace
                    throw;
                }
                cj.RunJob(job, servers[1], qObject); //this method will fail its own jobs

                CsvResponse csvResponse = new CsvResponse(qObject);
                response.Content = new PushStreamContent(csvResponse.WriteToStream, new MediaTypeHeaderValue("text/plain"));
                return response;
            }
            catch (Exception ex)
            {
                Exception ex2 = new Exception("Failed to execute a query", ex);
                ex2.Data["UserId"] = userid;
                throw ex2;
            }
        }
    }
}
