/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

using System.Diagnostics;

using System.Text.Json;
using System.Text.Json.Serialization;

using DXLib.Email;
using DXLib.Data;
using DXLib.Utils;

namespace DXLib.Log;

/*
 * Provides functionality for writing debug information at different verbosity levels. Low levels are echoed to the
 * console. Error levels are also persisted to a local log file, which can then be sent via email for troubleshooting.
 */
public static class DXLog
{
    /* Constants */

    // NA error code
	public const int CodeNA = -1;

    // Log cache key
    private const string LogKey = "LOG";

    // .zip file type
    private const string FileType = "application/gzip";

    // File attachment naming
    private const string FileName = "istatvball_troubleshooting_";
    private const string FileExt = ".isv";

    /* Methods */

    // VERBOSITY

    // Outputs an empty Trace level newline
    [Conditional( "DEBUG" )]
    public static void Trace()
    {
	    Console.WriteLine();
    }

    // Outputs a Trace level log message
    [Conditional( "DEBUG" )]
    public static void Trace( string msg, params object[] values )
    {
	    Console.WriteLine( msg, values );
    }

    // Outputs a Debug level log message
    [Conditional( "DEBUG" )]
    public static void Debug( string msg, params object[] values )
    {
	    Console.WriteLine( msg, values );
    }

    // Writes Error level log message to local log file
    public static void Error( string key )
    {
	    // Echo to console
	    Console.WriteLine( key );
		
	    DXLogFile file = GetFile();

	    // Add new entry
	    file.AddEntry( key );

	    // Persist
	    DXData.WriteCache( LogKey, file, true );
    }

    // Writes Error level log message, with additional data, to local log file
    public static void Error( string key, string msg, params object[] values )
    {
	    string error = string.Format( msg, values );
	    
	    // Echo to console
	    Console.WriteLine( $"{key}:{error}" );
		
	    DXLogFile file = GetFile();

	    // Add new entry
	    file.AddEntry( key, error );

	    // Persist
	    DXData.WriteCache( LogKey, file, true );
    }
    
    // Writes exception to local log file
	public static void Exception( string key, Exception ex, int code = CodeNA )
	{
		// Echo to console
		Console.WriteLine( $"{key}:{ex?.Message}({code})" );
		
		DXLogFile file = GetFile();

        // Add new entry
        file.AddEntry( key, ex, code );

        // Persist
		DXData.WriteCache( LogKey, file, true );
	}

	// FILE HANDLING
	
    // Sends local log via email with attached log file
    public static async Task<DXEmail.Result> Send()
    {
        // Get serialized file
        byte[] bytes = GetCompressedFile();

        // Build attachment name
        string date = DXUtils.FilenameFromDate( DXUtils.Now() );
        string filename = $"{FileName}{date}{FileExt}";

        // Async email send
        return await DXEmail.Send( new DXEmailConfig
        {
            IsLocal = true,

            // To:
            ToAddress = DXString.Get( "email.address" ),

            // Email config
            Subject = DXString.Get( "help.log.subject" ),
            Body = string.Empty,

            // Attachment
            FileRaw = bytes,
            FileName = filename,
            FileData = DXUtils.ToBase64( bytes ),
            FileType = FileType
        });
    }

    // Returns local log file, or new file if does not exist
    private static DXLogFile GetFile()
	{
		return DXData.ReadCache<DXLogFile>( LogKey ) ?? new DXLogFile();
    }

    // Returns local log file as GZIP compressed JSON
	private static byte[] GetCompressedFile()
	{
		DXLogFile file = GetFile();

        // Ignore nulls, ensure camel case JSON keys
        JsonSerializerOptions options = new()
        {
	        IgnoreReadOnlyProperties = true,
	        IgnoreReadOnlyFields = true,
	        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
	        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        // Serialize to JSON
        string json = JsonSerializer.Serialize( file, options );

        // GZIP compress
		return DXData.Compress( json );
    }
}

//
