using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using rockfishCore.Models;
using rockfishCore.Util;
using System.Linq;
using System;

//required to inject configuration in constructor
using Microsoft.Extensions.Configuration;

namespace rockfishCore.Controllers
{
    //Authentication controller
    public class AuthController : Controller
    {
        private readonly rockfishContext _context;
        private readonly IConfiguration _configuration;
        public AuthController(rockfishContext context, IConfiguration configuration)//these two are injected, see startup.cs
        {
            _context = context;
            _configuration = configuration;
        }

        //AUTHENTICATE CREDS 
        //RETURN JWT        

        [HttpPost("/authenticate")]
        public JsonResult PostCreds(string login, string password) //if was a json body then //public JsonResult PostCreds([FromBody] string login, [FromBody] string password)
        {
            int nFailedAuthDelay = 10000;

            if (string.IsNullOrWhiteSpace(login) || string.IsNullOrWhiteSpace(password))
            {
                //Make a failed pw wait
                System.Threading.Thread.Sleep(nFailedAuthDelay);
                return Json(new { msg = "authentication failed", error = 1 });
            }

//DANGER DANGER - this assumes all logins are different...boo bad code
//FIXME
//BUGBUG
//TODO
//ETC
/*HOW TO FIX: because of the salt during login it must assume multiple users with the same login and 
	fetch each in turn, get the salt, hash the entered password and compare to the password stored password 
    
    So, instead of singleordefault must be assumed to be a collection of users returned in this code:
    */
            var user = _context.User.SingleOrDefault(m => m.Login == login);

            if (user == null)
            {
                //Make a failed pw wait
                System.Threading.Thread.Sleep(nFailedAuthDelay);
                return Json(new { msg = "authentication failed", error = 1 });
            }

           // string pwnew=Hasher.hash(user.Salt,"2df5cc611ee485d4aa897350daa045caa4015147ae34c6b7b363f1def605d305");

            string hashed = Hasher.hash(user.Salt, password);
            if (hashed == user.Password)
            {
                //get teh secret from appsettings.json
                var secret = _configuration.GetSection("JWT").GetValue<string>("secret");
                byte[] secretKey = System.Text.Encoding.ASCII.GetBytes(secret);

                var iat = new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();
                var exp = new DateTimeOffset(DateTime.Now.AddDays(30)).ToUnixTimeSeconds();

                //Generate a download token and store it with the user account and return it for the client
                Guid g = Guid.NewGuid();
                string dlkey = Convert.ToBase64String(g.ToByteArray());
                dlkey = dlkey.Replace("=", "");
                dlkey = dlkey.Replace("+", "");

                user.DlKey = dlkey;
                user.DlKeyExp=exp;
                _context.User.Update(user);
                _context.SaveChanges();


                var payload = new Dictionary<string, object>()
                        {
                            { "iat", iat.ToString() },
                            { "exp", exp.ToString() },
                            { "iss", "rockfishCore" },
                            { "id", user.Id.ToString() }
                        };


                //NOTE: probably don't need Jose.JWT as am using Microsoft jwt stuff to validate routes so it should also be able to
                //issue tokens as well, but it looked cmplex and this works so unless need to remove in future keeping it.
                string token = Jose.JWT.Encode(payload, secretKey, Jose.JwsAlgorithm.HS256);
                //string jsonDecoded = Jose.JWT.Decode(token, secretKey);

                return Json(new
                {
                    ok = 1,
                    issued = iat,
                    expires = exp,
                    token = token,
                    dlkey = dlkey,
                    name = user.Name,
                    id = user.Id
                });
            }
            else
            {
                //Make a failed pw wait
                System.Threading.Thread.Sleep(nFailedAuthDelay);
                return Json(new { msg = "authentication failed", error = 1 });
            }
        }

        //------------------------------------------------------

    }//eoc
}//eons