/// <file>validation_rest.cs</file>
/// <version>1.0.0 (2026-06-30T07:17Z)</version>
/// <author>David Ireland &lt;https://di-mgt.com.au/contact&gt;</author>
/// <copyright>Copyright (c) 2026 DI Management Services Pty Ltd</copyright>
/// <license>SPDX-License-Identifier: Apache-2.0</license>
/// <summary>REST validation client for the FirmaSAT validation service.</summary>
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace ValidationProject;

    public class Validator
    {
        /// <summary>
        /// Loads a certificate from a file path or returns the provided string if it's already in base64 or PEM format.
        /// </summary>
        /// <param name="certFileOrString">The file path to a certificate or a base64/PEM encoded certificate string.</param>
        /// <returns>A base64 encoded certificate string, or an empty string if no certificate is provided.</returns>
        private static string LoadCert(string certFileOrString)
        {
            return certFileOrString.Length == 0
                ? ""
                : File.Exists(certFileOrString)
                    ? Convert.ToBase64String(X509CertificateLoader.LoadCertificateFromFile(certFileOrString).RawData)
                    : certFileOrString;
        }

        /// <summary>
        /// Validates the supplied signed XML document against the remote FSA validation API.
        /// </summary>
        /// <param name="xmlFile">The path to the XML file to validate.</param>
        /// <param name="certFileOrString">
        /// An optional PAC certificate path or a certificate string in base64/PEM format.
        /// If empty, no PAC certificate is included in the request.
        /// </param>
        /// <returns>A task that completes after the validation request has been sent and the response has been printed.</returns>
        /// <remarks>
        /// The method reads the XML file, optionally loads a PAC certificate, serializes the payload as JSON,
        /// sends it to the configured validation endpoint, and writes the response to the console in formatted JSON.
        /// </remarks>
        public static async Task Validate(string xmlFile, string certFileOrString = "")
        {
            // Constants
            const string url = "https://di-mgt.com.au/cryptosys/api/fsa_validation";
            const string apiToken = "YOUR_API_TOKEN_HERE";  // Replace with your own api-token

            // Read in XML file to string
            string xmlContent = File.ReadAllText(xmlFile, Encoding.UTF8);
            XDocument xDoc = XDocument.Parse(xmlContent);
            string encodedXml = xDoc.ToString();

            // Read in optional PAC certificate
            string certContent = LoadCert(certFileOrString);

            // Create payload for REST request serialized for JSON
            var payload = new Dictionary<string, string>
            {
                ["api-token"] = apiToken,
                ["xmldata"] = encodedXml,
                ["pac-cert"] = certContent,
            };
            string jsonContent = JsonSerializer.Serialize(payload);

            using var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
            using var client = new HttpClient();

            string result;
            try
            {
                using HttpResponseMessage response = await client.PostAsync(url, content);
                response.EnsureSuccessStatusCode();
                result = await response.Content.ReadAsStringAsync();
            }
            catch (Exception ex)
            {
                result = $"Error: {ex.Message}";
            }

            // Display results in pretty-printed JSON
            var options = new JsonSerializerOptions { WriteIndented = true };
            try
            {
                var jsonNode = JsonNode.Parse(result);

                // Parse validation-result if it exists and is a string
                if (jsonNode?["validation-result"] != null && jsonNode["validation-result"]?.GetValueKind() == JsonValueKind.String)
                {
                    var validationResultString = jsonNode["validation-result"]?.GetValue<string>();
                    if (validationResultString != null)
                    {
                        jsonNode["validation-result"] = JsonNode.Parse(validationResultString);
                    }
                }

                Console.WriteLine(jsonNode?.ToJsonString(options));
            }
            catch
            {
                Console.WriteLine(result);
            }
        }
    }

public class ValidationApp
{
        public static async Task Main(string[] args)
        {
            // These two files must exist in the CWD
            await Validator.Validate("cfdv40-ejemplo-signed-tfd.xml", "pac.cer");
        }
}