using System.Collections.Generic;
using System.Linq;
using PolyTrader.Modules.CopyTrading.ConfigImport;
using Xunit;

namespace PolyTrader.Tests
{
    /// <summary>
    /// Sichert das robuste Parsen der mongoexport-JSON ab: Dezimalwerte als Strings,
    /// null-Felder, fehlende Felder → Default, Account-Arrays.
    /// </summary>
    public class MongoExportParserTests
    {
        [Fact]
        public void ParseAccounts_reads_core_fields_and_string_decimals()
        {
            const string json = """
            [{
              "_id": 1,
              "Name": "Richard Test",
              "WalletAddress": "0x628",
              "IsDemo": false,
              "IsActive": true,
              "TotalBalance": "64.763626",
              "AvailableBalance": "1.155226"
            }]
            """;

            var imp = Assert.Single(MongoExportParser.ParseAccounts(json));
            Assert.Equal(1, imp.Account.AccountId);
            Assert.Equal("Richard Test", imp.Account.Name);
            Assert.Equal("0x628", imp.Account.WalletAddress);
            Assert.False(imp.Account.IsDemo);
            Assert.True(imp.Account.IsActive);
            Assert.Equal(64.763626m, imp.Account.TotalBalance);
            Assert.Equal(1.155226m, imp.Account.AvailableBalance);
        }

        [Fact]
        public void ParseAccounts_maps_old_limit_fields_into_settings()
        {
            const string json = """
            [{ "_id": 3, "PerMarketLimit": "10", "PerMasterLimit": "20", "MaxBuyPrice": "0.85", "PreRedeemLimit": "99.5" }]
            """;

            var imp = Assert.Single(MongoExportParser.ParseAccounts(json));
            Assert.Equal(3, imp.Settings.AccountId);
            Assert.Equal(10m, imp.Settings.PerMarketLimit);
            Assert.Equal(20m, imp.Settings.PerMasterLimit);
            Assert.Equal(0.85m, imp.Settings.MaxBuyPrice);
            Assert.Equal(99.5m, imp.Settings.PreRedeemLimit);
        }

        [Fact]
        public void ParseAccounts_null_string_falls_back_to_empty()
        {
            const string json = """[{ "_id": 3, "PayoutAddress": null }]""";

            var imp = Assert.Single(MongoExportParser.ParseAccounts(json));
            Assert.Equal(string.Empty, imp.Account.PayoutAddress);
        }

        [Fact]
        public void ParseAccounts_missing_settings_fields_use_defaults()
        {
            const string json = """[{ "_id": 1 }]""";

            var imp = Assert.Single(MongoExportParser.ParseAccounts(json));
            Assert.Equal(5.0m, imp.Settings.PerMarketLimit);
            Assert.Equal(2.0m, imp.Settings.MaxPriceDifference);
            Assert.Equal(0.98m, imp.Settings.MaxBuyPrice);
            Assert.Equal(40.0m, imp.Settings.perMaxTimeNone);
        }

        [Fact]
        public void ParseTraders_reads_fields_and_assigned_accounts()
        {
            const string json = """
            [{
              "_id": 2,
              "WalletAddress": "0xa2711",
              "DisplayName": "0xa2711",
              "Category": "TRADING_BOT",
              "IsActive": false,
              "TotalTrades": 32,
              "TotalPnl": 7386.655743958501,
              "AssignedAccountIds": [1, 3],
              "Description": null
            }]
            """;

            var t = Assert.Single(MongoExportParser.ParseTraders(json));
            Assert.Equal(2, t.Id);
            Assert.Equal("TRADING_BOT", t.Category);
            Assert.False(t.IsActive);
            Assert.Equal(32, t.TotalTrades);
            Assert.Equal(7386.655743958501, t.TotalPnl, 6);
            Assert.Equal(new HashSet<int> { 1, 3 }, t.AssignedAccountIds);
            Assert.Equal(string.Empty, t.Description);
        }

        [Fact]
        public void ParseTraders_missing_category_uses_default()
        {
            const string json = """[{ "_id": 5, "DisplayName": "x" }]""";

            var t = Assert.Single(MongoExportParser.ParseTraders(json));
            Assert.Equal("NEW_BIG_BET", t.Category);
            Assert.Empty(t.AssignedAccountIds);
        }

        [Fact]
        public void Parse_returns_empty_for_non_array_or_empty()
        {
            Assert.Empty(MongoExportParser.ParseAccounts("{}"));
            Assert.Empty(MongoExportParser.ParseAccounts("[]"));
            Assert.Empty(MongoExportParser.ParseTraders("[]"));
        }

        [Fact]
        public void ParseAccounts_accepts_numeric_decimals_not_only_strings()
        {
            const string json = """[{ "_id": 1, "TotalBalance": 12.5, "PerMarketLimit": 3 }]""";

            var imp = Assert.Single(MongoExportParser.ParseAccounts(json));
            Assert.Equal(12.5m, imp.Account.TotalBalance);
            Assert.Equal(3m, imp.Settings.PerMarketLimit);
        }

        [Fact]
        public void ParseAccounts_ignores_unknown_extra_fields()
        {
            const string json = """[{ "_id": 1, "Name": "X", "SomethingUnknown": {"a":1}, "Extra": [1,2,3] }]""";

            var imp = Assert.Single(MongoExportParser.ParseAccounts(json));
            Assert.Equal("X", imp.Account.Name);
        }

        [Fact]
        public void ParseAccounts_reads_multiple_documents_in_order()
        {
            const string json = """[{ "_id": 1 }, { "_id": 2 }, { "_id": 3 }]""";

            var ids = MongoExportParser.ParseAccounts(json).Select(x => x.Account.AccountId).ToArray();
            Assert.Equal(new[] { 1, 2, 3 }, ids);
        }

        [Fact]
        public void ParseTraders_accepts_assigned_account_ids_as_string_numbers()
        {
            const string json = """[{ "_id": 9, "AssignedAccountIds": ["1", "3"] }]""";

            var t = Assert.Single(MongoExportParser.ParseTraders(json));
            Assert.Equal(new HashSet<int> { 1, 3 }, t.AssignedAccountIds);
        }

        [Fact]
        public void ParseTraders_missing_isactive_defaults_true()
        {
            const string json = """[{ "_id": 9 }]""";

            var t = Assert.Single(MongoExportParser.ParseTraders(json));
            Assert.True(t.IsActive);
        }
    }
}
