using System.Net;
using System.Text;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;

namespace Server
{
    public class Login
    {
        private static string secretKey = "stronk-key-much-sercret-much-more-stronk-stronk-key-much-sercret-much-more-stronk";

        public static string GenerateToken(string user)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                issuer: "TimeLogServer",
                audience: "TimeLogWebsite",
                claims: new[]
                {
                new Claim(ClaimTypes.Name, user)
                },
                expires: DateTime.Now.AddHours(2),
                signingCredentials: creds
            );

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        public static bool VerifyPassword(string enteredPassword, string storedHash)
        {
            byte[] hashBytes = Convert.FromBase64String(storedHash);

            // Extract the salt from the stored hash
            byte[] salt = new byte[16];
            Array.Copy(hashBytes, 0, salt, 0, 16);

            // Hash the entered password with the stored salt
            using (var pbkdf2 = new Rfc2898DeriveBytes(enteredPassword, salt, 10000, HashAlgorithmName.SHA256))
            {
                byte[] newHash = pbkdf2.GetBytes(32);

                // Compare the computed hash with the stored hash
                for (int i = 0; i < 32; i++)
                {
                    if (newHash[i] != hashBytes[i + 16])
                        return false;
                }
                return true;
            }
        }

        public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
        {
            try
            {
                conn.Open();
                // prepare SQL query
                MySqlCommand cmd = new MySqlCommand();
                cmd.Connection = conn;
                cmd.CommandText = @"SELECT u.id,password FROM User u 
                  INNER JOIN Password p ON p.user=u.id 
                  WHERE mail=@mail";
                var queryString = request.QueryString;
                string? mail = queryString["mail"];
                string? password = queryString["password"];
                cmd.Parameters.AddWithValue("@mail", mail);
                cmd.Parameters.AddWithValue("@password", password);
                // execute query and read results
                MySqlDataReader reader = cmd.ExecuteReader();

                string? userId = "";
                string? hashedPass = "";
                string? jsonResponse;
                while (reader.Read())
                {
                    userId = Convert.ToString(reader["id"]);
                    hashedPass = Convert.ToString(reader["password"]);
                }

                // check username
                if (string.IsNullOrEmpty(userId) && string.IsNullOrEmpty(hashedPass))
                {
                    throw new Exception("Error:Invalid Username or Password");
                }

                //check password
                if (string.IsNullOrEmpty(password)
                    || string.IsNullOrEmpty(hashedPass)
                    || VerifyPassword(password, Convert.ToString(hashedPass)))
                {
                    throw new Exception("Error:Invalid Username or Password");
                }

                jsonResponse = JsonConvert.SerializeObject(GenerateToken(userId));

                // prepare response
                byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
                response.ContentType = "application/json";
                response.ContentLength64 = buffer.Length;
                response.OutputStream.Write(buffer, 0, buffer.Length);
            }
            catch (Exception ex)
            {
                string errorMessage = $"Error: {ex.Message}";
                byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
                response.ContentType = "text/plain";
                response.ContentLength64 = buffer.Length;
                response.OutputStream.Write(buffer, 0, buffer.Length);
            }
            finally
            {
                // close db connection
                conn.Close();
            }
        }
    }
}

