using System.Net;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;

namespace TimelogBackend;

// there should be a better way to deal with data comming from sql
public class Log
{
    public object? FName { get; set; }
    public object? LName { get; set; }
    public object? Mail { get; set; }
    public object? Name { get; set; }
    public object? Time { get; set; }
    public object? Date { get; set; }
    public object? User { get; set; }
}

public class Getall : Route
{
    private static string ConstructQuery(
        string from,
        string to,
        string order,
        string offset,
        string sortby
    )
    {
        string mainQuery =
            @"SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user 
                                     FROM Timelog t 
                                     INNER JOIN Project p ON p.id=t.project 
                                     INNER JOIN User u ON u.id=t.user ";
        // this shenanigan is needed to remove the "" around group by
        string offsetQuery = " LIMIT 10 OFFSET " + offset + ";";
        // depending on the incoming parameters construct a Query
        if (!string.IsNullOrEmpty(to) && !string.IsNullOrEmpty(from))
        {
            mainQuery += AddWhereClause(from, to);
        }
        if (!string.IsNullOrEmpty(sortby))
        {
            mainQuery += AddSortBy(sortby, order);
        }
        if (!int.TryParse(offset, out int myInt) || myInt < 0)
            throw new Exception("Incorect offset");

        return mainQuery + offsetQuery;
    }

    private static string AddWhereClause(string from, string to)
    {
        if (!ValidateDate(to) || !ValidateDate(from))
        {
            throw new Exception("Incorrect date format");
        }
        string whereQuery = " WHERE t.date BETWEEN @from AND @to ";
        return whereQuery;
    }

    private static string AddSortBy(string sortby, string order)
    {
        List<string> validSorting = ["f_name", "l_name", "mail", "time", "date", "user", "project"];
        if (!validSorting.Contains(sortby))
        {
            throw new Exception("Incorrect sorting value");
        }
        string orderQuery = " ORDER BY " + sortby + " " + order;
        return orderQuery;
    }

    private static List<Log> ExtractDataFromDB(MySqlCommand cmd)
    {
        using MySqlConnection conn = new(connectionString);
        conn.Open();
        cmd.Connection = conn;
        // execute query and read results
        MySqlDataReader reader = cmd.ExecuteReader();

        List<Log> entries = [];
        while (reader.Read())
        {
            entries.Add(
                new Log
                {
                    FName = reader["f_name"],
                    LName = reader["l_name"],
                    User = reader["user"],
                    Date = reader["date"],
                    Name = reader["name"],
                    Time = reader["time"],
                    Mail = reader["mail"],
                }
            );
        }
        return entries;
    }

    public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
    {
        try
        {
            // extract data from url
            var queryString = request.QueryString;
            string? from = queryString["from"] ?? "";
            string? to = queryString["to"] ?? "";
            string? sortby = queryString["sortby"] ?? "";
            string? offset = queryString["offset"] ?? "";
            string? order = queryString["order"] ?? "";
            order = order == "true" ? "ASC" : "DESC";
            // SQL
            MySqlCommand cmd = new(ConstructQuery(from, to, order, offset, sortby));
            cmd.Parameters.AddWithValue("@from", from);
            cmd.Parameters.AddWithValue("@to", to);
            var entries = ExtractDataFromDB(cmd);

            // serialize JSON
            string jsonResponse = JsonConvert.SerializeObject(entries);
            SendSuccess(response, jsonResponse);
        }
        catch (Exception ex)
        {
            SendError(response, ex);
        }
    }
}
