using System.Collections.Generic;
using System.Threading.Tasks;
using QuantEngine.Core.Domain;
using QuantEngine.Core.Interfaces;

namespace QuantEngine.Application.Services
{
    public class FormulaService
    {
        private readonly IPostgresqlHistoryStore _historyStore;
        private readonly DecisionLearningService _learningService;

        public FormulaService(IPostgresqlHistoryStore historyStore, DecisionLearningService learningService)
        {
            _historyStore = historyStore;
            _learningService = learningService;
        }

    public TimingDecisionResult ComputeTimingDecision(Dictionary<string, object> ctx)
            => FormulaEngine.ComputeTimingDecision(RequireContext(ctx));

    public SellDecisionResult ComputeSellDecision(Dictionary<string, object> ctx)
            => FormulaEngine.ComputeSellDecision(RequireContext(ctx));

    public FinalDecisionResult ComputeFinalDecision(Dictionary<string, object> ctx)
            => FormulaEngine.ComputeFinalDecision(RequireContext(ctx));

        public async Task<Guid> ComputeAndRecordFinalDecisionAsync(
            Dictionary<string, object> ctx,
            string decisionKey,
            string instrumentId,
            string sourceVersion,
            IEnumerable<FactorEvidenceInput> factorEvidence)
        {
            var normalizedContext = RequireContext(ctx);
            var decision = ComputeFinalDecision(normalizedContext);
            return await _learningService.RecordDecisionAsync(
                RequireValue(decisionKey, nameof(decisionKey)),
                DateTimeOffset.UtcNow,
                RequireValue(instrumentId, nameof(instrumentId)),
                decision.FinalAction,
                "PASS",
                Convert.ToDecimal(decision.PriorityScore),
                RequireValue(sourceVersion, nameof(sourceVersion)),
                factorEvidence,
                new { context_keys = normalizedContext.Keys.OrderBy(key => key).ToArray() },
                new { formula = "FormulaEngine.ComputeFinalDecision", source_version = sourceVersion });
        }

        public CashShortfallResult ComputeCashShortfallHarness(
            Dictionary<string, object> asResult,
            double totalAsset,
            Dictionary<string, object> cashFloorInfo,
            double mrsScore)
            => FormulaEngine.ComputeCashShortfallHarness(asResult, totalAsset, cashFloorInfo, mrsScore);

        public CashRecoveryPlanResult ComputeCashRecoveryOptimizer(
            List<Dictionary<string, object>> sellCandidates,
            double cashShortfallMinKrw)
            => FormulaEngine.ComputeCashRecoveryOptimizer(sellCandidates, cashShortfallMinKrw);

        public Task<int> AppendFormulaRunAsync(string formulaName, Dictionary<string, object?> payload)
            => _historyStore.AppendAsync($"formula_{RequireValue(formulaName, nameof(formulaName))}_history", payload);

        private static Dictionary<string, object> RequireContext(Dictionary<string, object> ctx)
        {
            ArgumentNullException.ThrowIfNull(ctx);
            return ctx;
        }

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

            return value.Trim();
        }
    }
}
