using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.IdentityModel.Tokens;
using MySql.Data.MySqlClient;
using Newtonsoft.Json.Linq;

namespace TimelogBackend;

public class CreateLog : Route
{
    private static readonly string secretKey =
        "stronk-key-much-sercret-much-more-stronk-stronk-key-much-sercret-much-more-stronk";

    public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
    {
        try
        {
            // check header
            var headers = request.Headers;
            string token = headers["token"] ?? "";
            if (!string.IsNullOrEmpty(token) && !ValidateToken(token))
            {
                throw new Exception("Invalid token");
            }

            MySqlCommand cmd = new();

            string body;
            using (StreamReader bodyReader = new(request.InputStream, request.ContentEncoding))
            {
                body = bodyReader.ReadToEnd();
            }
            JObject jsonObject = JObject.Parse(body);
            string project = jsonObject["project"]?.ToString() ?? "";
            string time = jsonObject["time"]?.ToString() ?? "";
            string date = jsonObject["date"]?.ToString() ?? "";

            // TODO check if the hours on given date don't combine to more
            // than 8

            if (!ValidateTime(time))
            {
                throw new Exception("Incorrect date format");
            }
            if (!ValidateDate(date))
            {
                throw new Exception("Incorrect date format");
            }
            // validate user
            string? usernameClaim = GetUserFromToken(token);
            if (string.IsNullOrEmpty(usernameClaim))
            {
                throw new Exception("wrong user id");
            }
            // validate project
            // TODO better project validation
            if (string.IsNullOrEmpty(project))
            {
                throw new Exception("wrong project");
            }
            SaveTimeLogToDatabase(usernameClaim, project, date, time);
            SendSuccess(response);
        }
        catch (Exception ex)
        {
            SendError(response, ex);
        }
    }

    private static bool ValidateToken(string token)
    {
        try
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
            var tokenHandler = new JwtSecurityTokenHandler();
            var validationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidIssuer = "TimeLogServer",
                ValidAudience = "TimeLogWebsite",
                IssuerSigningKey = key,
            };

            var principal = tokenHandler.ValidateToken(
                token,
                validationParameters,
                out SecurityToken validatedToken
            );
            return validatedToken != null;
        }
        catch
        {
            return false;
        }
    }

    private static bool ValidateTime(string time)
    {
        return int.TryParse(time, out int myInt) && myInt >= 0 && myInt <= 8;
    }

    private static string GetUserFromToken(string token)
    {
        var handler = new JwtSecurityTokenHandler();
        var jwtToken = handler.ReadJwtToken(token);
        string? usernameClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == "user")?.Value;
        return string.IsNullOrEmpty(usernameClaim) ? "" : usernameClaim;
    }

    private static void SaveTimeLogToDatabase(
        string username,
        string project,
        string date,
        string time
    )
    {
        using MySqlConnection conn = new(connectionString);
        conn.Open();
        using MySqlCommand cmd = new(
            @"INSERT INTO Timelog(user, project, date, time) 
               VALUES(@user, @project, @date, @time);",
            conn
        );
        cmd.Parameters.AddWithValue("@user", username);
        cmd.Parameters.AddWithValue("@project", project);
        cmd.Parameters.AddWithValue("@date", date);
        cmd.Parameters.AddWithValue("@time", time);
        cmd.ExecuteNonQuery();
    }
}
