using System.Text.Json;
using QuantEngine.Core.Domain;
using QuantEngine.Core.Interfaces;
using QuantEngine.Application.Interfaces;

namespace QuantEngine.Application.Services;

public sealed record FactorComputationAudit(
    string Ticker,
    int StockBars,
    int IndexBars,
    string State,
    DateTimeOffset ComputedAt,
    string? SourceVersion);

public sealed class FactorComputationService
{
    private readonly HistoryIngestionService _history;
    private readonly IRuntimeAuditTrailService _auditTrail;

    public FactorComputationService(HistoryIngestionService history, IRuntimeAuditTrailService auditTrail)
    {
        _history = history;
        _auditTrail = auditTrail;
    }

    public FactorOutputs Compute(
        string ticker,
        List<PriceHistoryDailyRecord> stockBars,
        List<PriceHistoryDailyRecord> indexBars,
        string? sourceVersion = null)
    {
        var computedAt = DateTimeOffset.UtcNow;
        var outputs = FactorCalculator.CalculateFactors(stockBars, indexBars);
        _auditTrail.Append("factor_audit", ticker, new FactorComputationAudit(ticker, stockBars.Count, indexBars.Count, "SUCCEEDED", computedAt, sourceVersion));
        return outputs;
    }

    public async Task AppendFactorOutputsAsync(
        string ticker,
        string sourceVersion,
        FactorOutputs outputs,
        DateTimeOffset? observedAt = null)
    {
        ticker = RequireValue(ticker, nameof(ticker));
        sourceVersion = RequireValue(sourceVersion, nameof(sourceVersion));
        ArgumentNullException.ThrowIfNull(outputs);

        var when = observedAt ?? DateTimeOffset.UtcNow;
        await _history.AppendFactorOutputAsync("momentum_20d", sourceVersion, outputs.Momentum20D, "PASS", sourceVersion, when);
        await _history.AppendFactorOutputAsync("momentum_60d", sourceVersion, outputs.Momentum60D, "PASS", sourceVersion, when);
        await _history.AppendFactorOutputAsync("momentum_120d", sourceVersion, outputs.Momentum120D, "PASS", sourceVersion, when);
        await _history.AppendFactorOutputAsync("atr_20pct", sourceVersion, outputs.Atr20Pct, "PASS", sourceVersion, when);
        await _history.AppendFactorOutputAsync("stdev_20d", sourceVersion, outputs.StDev20D, "PASS", sourceVersion, when);
        await _history.AppendFactorOutputAsync("beta_60d", sourceVersion, outputs.Beta60D, "PASS", sourceVersion, when);
        await _history.AppendFactorOutputAsync("rs_20d", sourceVersion, outputs.Rs20D, "PASS", sourceVersion, when);
        _auditTrail.Append("factor_audit", ticker, new FactorComputationAudit(ticker, 0, 0, "PERSISTED", when, sourceVersion));
    }

    private static string RequireValue(string value, string parameterName)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentException("Value is required.", parameterName);
        }

        return value.Trim();
    }
}
