using EonaCat.Json;

namespace EonaCat.Logger.Servers.Splunk;

using EonaCat.Logger.Servers.Splunk.Models;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

/// <summary>
///     Splunk Server.
/// </summary>
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

public class Splunk : IDisposable
{
    internal readonly object SendLock = new();
    private string _splunkHecUrl = "https://127.0.0.1:8088/services/collector/event";

    public string SplunkHecToken { get; set; } = "splunk-hec-token";
    public HttpClientHandler SplunkClientHandler { get; private set; }
    public HttpClient HttpClient { get; private set; }
    public string Nickname { get; set; }

    public bool HasHecToken => !string.IsNullOrWhiteSpace(SplunkHecToken) && SplunkHecToken != "splunk-hec-token";
    public bool HasHecUrl => !string.IsNullOrWhiteSpace(SplunkHecUrl);
    public bool IsHttpsHecUrl => HasHecUrl && _splunkHecUrl.ToLower().StartsWith("https");
    public bool IsLocalHost => HasHecUrl && (_splunkHecUrl.ToLower().Contains("127.0.0.1") || _splunkHecUrl.ToLower().Contains("localhost"));

    /// <summary>
    /// Splunk Server
    /// </summary>
    /// <param name="splunkHecUrl"></param>
    /// <param name="splunkHecToken"></param>
    /// <param name="httpClientHandler"></param>
    /// <param name="nickName"></param>
    /// <param name="typesToLog"></param>
    /// <exception cref="ArgumentNullException"></exception>
    public Splunk(string splunkHecUrl, string splunkHecToken, HttpClientHandler httpClientHandler = null, string nickName = null, List<ELogType> typesToLog = null)
    {
        SplunkHecUrl = splunkHecUrl ?? throw new ArgumentNullException(nameof(splunkHecUrl));
        SplunkHecToken = splunkHecToken ?? throw new ArgumentNullException(nameof(splunkHecToken));

        Nickname = nickName ?? $"{splunkHecUrl}_{splunkHecToken}";
        SplunkClientHandler = httpClientHandler ?? new HttpClientHandler();
        TypesToLog = typesToLog;

        CreateHttpClient();
    }

    public string SplunkHecUrl
    {
        get => _splunkHecUrl;
        set
        {
            if (!string.IsNullOrWhiteSpace(value) && !value.ToLower().Contains("http"))
            {
                value = $"http://{value}";
            }

            _splunkHecUrl = value;
            CreateHttpClient();
        }
    }

    public List<ELogType> TypesToLog { get; set; }

    private void CreateHttpClient()
    {
        DisposeHttpClient();

        SplunkClientHandler ??= new HttpClientHandler();
        HttpClient = new HttpClient(SplunkClientHandler)
        {
            BaseAddress = new Uri(SplunkHecUrl)
        };

        HttpClient.DefaultRequestHeaders.Add("Authorization", $"Splunk {SplunkHecToken}");
    }

    public void DisableSSLValidation()
    {
        DisposeHttpClient();

        SplunkClientHandler = new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
        };

        CreateHttpClient();
    }

    public async Task<HttpResponseMessage> SendAsync(SplunkPayload splunkPayload, bool disableSplunkSSL = false)
    {
        if (splunkPayload == null) return null;

        var eventObject = new
        {
            @event = splunkPayload.EventData,
            sourcetype = splunkPayload.SourceType,
            host = splunkPayload.Host
        };

        if (disableSplunkSSL)
        {
            DisableSSLValidation();
        }

        if (HttpClient == null)
        {
            CreateHttpClient();
        }

        var eventJson = JsonHelper.ToJson(eventObject);
        if (!HasHecToken) CreateHttpClient();

        using var content = new StringContent(eventJson, Encoding.UTF8, "application/json");
        return await HttpClient.PostAsync("/services/collector/event", content);
    }

    internal void DisposeHttpClient()
    {
        if (HttpClient != null)
        {
            HttpClient.Dispose();
            HttpClient = null;
        }

        if (SplunkClientHandler != null)
        {
            SplunkClientHandler.Dispose();
            SplunkClientHandler = null;
        }
    }

    public void Dispose()
    {
        DisposeHttpClient();
        GC.SuppressFinalize(this);
    }

    ~Splunk()
    {
        Dispose();
    }
}