using System.Diagnostics;
using System.Net.Http.Headers;
using System.Text.Json;
using Microsoft.AspNetCore.OData.Routing.Controllers;
using Microsoft.Identity.Client;

namespace Fast.Web.Logic;

public class BcApiHelper() : ODataController
{
    private const string ClientId = "0061481e-33a5-429b-aaba-b3d76687a497";
    private const string ClientSecret = "2pT8Q~3iwCwzW4STRf5k4IP.1NX34fXMYkcIFcsn";
    private const string TenantId = "93e3e76b-c333-4adf-b4b2-4c1b7119c12f";
    private const string EnvironmentName = "SNGC_DEV_SANDBOX_110925";
    private const string CompanyId = "aae7a268-538e-f011-b419-7c1e521affd5"; // Superior Natural Gas, got manually from GetCompaniesAsync
    private static readonly string Authority = $"https://login.microsoftonline.com/{TenantId}";
    private static readonly string[] Scopes = new string[] { "https://api.businesscentral.dynamics.com/.default" };
    private static readonly string BaseUrl = $"https://api.businesscentral.dynamics.com/v2.0/{TenantId}/{EnvironmentName}";

    private static readonly JsonSerializerOptions CamelCaseOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
    private static readonly JsonSerializerOptions CaseInsensitiveOptions = new() { PropertyNameCaseInsensitive = true };

    private readonly HttpClient client = new();

    public async Task Authenticate()
    {
        Debug.WriteLine("Authenticating...");
        var accessToken = await GetAccessTokenAsync();
        Debug.WriteLine("Authentication successful.");

        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.Timeout = TimeSpan.FromMinutes(20);
    }

    private static async Task<string> GetAccessTokenAsync()
    {
        // Using MSAL (Microsoft.Identity.Client) for OAuth2 Client Credentials Flow
        IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(ClientId)
            .WithClientSecret(ClientSecret)
            .WithAuthority(new Uri(Authority))
            .Build();

        AuthenticationResult result = await app.AcquireTokenForClient(Scopes).ExecuteAsync();
        return result.AccessToken;
    }

    public async Task CreateInvoiceAsync(Models.BcInvoice inv)
    {
        var url = $"{BaseUrl}/api/SuperiorNaturalGasCorporation/sales/v2.0/companies({CompanyId})/superiorInvoiceRequests";

        var json = JsonSerializer.Serialize(inv, CamelCaseOptions);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await client.PostAsync(url, content);

        if (response.IsSuccessStatusCode)
            Debug.WriteLine($"{inv.Number} created successfully.");
        else
        {
            var error = await response.Content.ReadAsStringAsync();
            throw new Exception($"BC API error creating {inv.Number}: {error}");
        }
    }

    public async Task<Dictionary<string, BcInvoice>> FetchExistingInvoicesAsync()
    {
        var url = $"{BaseUrl}/api/v2.0/companies({CompanyId})/salesInvoices?$filter=status eq 'Open' or status eq 'Paid'";

        var response = await client.GetAsync(url);

        if (!response.IsSuccessStatusCode)
        {
            var error = await response.Content.ReadAsStringAsync();
            throw new Exception($"BC API error fetching invoices: {error}");
        }

        var json = await response.Content.ReadAsStringAsync();

        using var doc = JsonDocument.Parse(json);

        if (!doc.RootElement.TryGetProperty("value", out var valueElement)
            || valueElement.ValueKind != JsonValueKind.Array)
        {
            return new Dictionary<string, BcInvoice>(StringComparer.OrdinalIgnoreCase);
        }

        var invoices = JsonSerializer.Deserialize<List<BcInvoice>>(
            valueElement.GetRawText(),
            CaseInsensitiveOptions
        ) ?? [];

        return invoices
            .Where(i => !string.IsNullOrWhiteSpace(i.Number))
            .ToDictionary(i => i.Number, StringComparer.OrdinalIgnoreCase);
    }
}
