using System;
using System.Collections.Generic;
using System.Linq;
using NBitcoin;
using NBitcoin.BouncyCastle.Math;
using NBitcoin.DataEncoders;
using NBitcoin.Protocol;
using Stratis.Bitcoin.Networks.Deployments;

namespace Stratis.Bitcoin.Networks
{
    public class DeStreamTest : DeStreamMain
    {
        public DeStreamTest()
        {// The message start string is designed to be unlikely to occur in normal data.
            // The characters are rarely used upper ASCII, not valid as UTF-8, and produce
            // a large 4-byte int at any alignment.
            var messageStart = new byte[4];
            messageStart[0] = 0xFD;
            messageStart[1] = 0xFC;
            messageStart[2] = 0xFC;
            messageStart[3] = 0xFD;
            uint magic = BitConverter.ToUInt32(messageStart, 0);

            this.Name = "DeStreamTest";
            this.Magic = magic;
            this.DefaultPort = 56849;
            this.RPCPort = 56848;
            this.CoinTicker = "TDST";
            
            var consensusFactory = new PosConsensusFactory();
            
            // Create the genesis block.
            var initialWalletAddresses = new[]
            {
                "TrpCjf3qT6QXckyXqF8nT1rCQzD2g8S6ES",
                "Tqe8mF9go4eie1gukcchHRFKFEfd3X75dc",
                "TqgsrrXENYgiginKbxvfTbeWRPYtR4NdMM",
                "TiG1yaj7qaFfX8C4aj4T4DQK5KUxmbLGra",
                "ThvAAkHQNbHUegDe7Y4AVFJuDeMZHSkU2m",
                "TboaVBt66aZcFE7EhBwWrm5jCL9Xu832Ho",
                "Tw5FZ1FrCCNkHD68GEbt7LvovoAj2zfmia",
                "TmwSHokx4v2yWiUBpen5zx9Laxf5Kvzcn7",
                "ThxztyUpm2ak44pBTcQvbRc9ERHgfP72DV",
                "Tmewpbmy6SDsyZHszVfizEsR66grcJAf3J",
                "Tg4P3HfrTprrUi2fyxzp5qYcXB2nYXgdmV",
                "TetkuZ1vQVteMd4BARVcN2x9YjbXyUirPW",
                "TvAkCawusnDEyNJLMRohEaKeyoGGK6Lz4B",
                "TpfBFwygXdzq3DWrzUXDvHRcin4RsHQbhV",
                "TuqX4d9tRHzq7Yf9uuEXLZEUkBuKuLsc5L",
                "ThzLVN9n9U3AGZVgWU1b561WBR9TEN6XbD",
                "TcktjDxbrNqdgW84xwesWG7hJphnVvUDSb",
                "Tnp7gDYkQ3MtFVXQ3ZgkrZGmRErdqcdRQM",
                "TvZ1syCg7ffJLX7Y2GCAZtYGXbJDrvNZy3",
                "TgnFxUtqFsMXRm5kksd6o59njSCu67QeNi"
            };
            const decimal initialCoins = 6000000000;
            
            var powLimit = new Target(new uint256("0000ffff00000000000000000000000000000000000000000000000000000000"));
            
            this.GenesisTime = (uint) new DateTimeOffset(2019, 2, 11, 0, 0, 0, new TimeSpan()).ToUnixTimeSeconds();
            this.GenesisNonce = 1831645;
            this.GenesisBits = powLimit;
            this.GenesisVersion = 1;
            this.GenesisReward = Money.Coins(initialCoins);
            this.GenesisWalletAddress = initialWalletAddresses.First();

            var genesisBlock = this.CreateDeStreamGenesisBlock(this.Consensus.ConsensusFactory, this.GenesisTime,
                this.GenesisNonce, this.GenesisBits, this.GenesisVersion, this.GenesisReward,
                initialWalletAddresses);
            
            genesisBlock.Header.Time = (uint) new DateTimeOffset(2019, 2, 11, 12, 0, 0, new TimeSpan()).ToUnixTimeSeconds();
            genesisBlock.Header.Nonce = 2433759;
            genesisBlock.Header.Bits = powLimit;
            
            this.Genesis = genesisBlock;
            
            // Taken from StratisX.
            var consensusOptions = new PosConsensusOptions(
                maxBlockBaseSize: 1_000_000,
                maxStandardVersion: 2,
                maxStandardTxWeight: 100_000,
                maxBlockSigopsCost: 20_000,
                maxStandardTxSigopsCost: 20_000 / 5
            );
            
            var buriedDeployments = new BuriedDeploymentsArray
            {
                [BuriedDeployments.BIP34] = 0,
                [BuriedDeployments.BIP65] = 0,
                [BuriedDeployments.BIP66] = 0
            };
            
            var bip9Deployments = new StratisBIP9Deployments()
            {
                [StratisBIP9Deployments.ColdStaking] = new BIP9DeploymentsParameters(2,
                    new DateTime(2018, 12, 1, 0, 0, 0, DateTimeKind.Utc),
                    new DateTime(2019, 12, 1, 0, 0, 0, DateTimeKind.Utc))
            };//TODO: BIP9

            
            this.Consensus = new NBitcoin.Consensus(
                consensusFactory: consensusFactory,
                consensusOptions: consensusOptions,
                coinType: 1,
                hashGenesisBlock: genesisBlock.GetHash(),
                subsidyHalvingInterval: 210000,
                majorityEnforceBlockUpgrade: 750,
                majorityRejectBlockOutdated: 950,
                majorityWindow: 1000,
                buriedDeployments: buriedDeployments,
                bip9Deployments: bip9Deployments, 
                bip34Hash: new uint256("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"),
                ruleChangeActivationThreshold: 1916, // 95% of 2016
                minerConfirmationWindow: 2016, // nPowTargetTimespan / nPowTargetSpacing
                maxReorgLength: 500,
                defaultAssumeValid: new uint256("0x98fa6ef0bca5b431f15fd79dc6f879dc45b83ed4b1bbe933a383ef438321958e"), // 795970
                maxMoney: long.MaxValue,
                coinbaseMaturity: 10,
                premineHeight: 0,
                premineReward: Money.Zero,
                proofOfWorkReward: Money.Zero,
                powTargetTimespan: TimeSpan.FromSeconds(14 * 24 * 60 * 60), // two weeks
                powTargetSpacing: TimeSpan.FromSeconds(10 * 60),
                powAllowMinDifficultyBlocks: false,
                powNoRetargeting: false,
                powLimit: powLimit,
                minimumChainWork: null,
                isProofOfStake: true,
                lastPowBlock: 1000,
                proofOfStakeLimit: new BigInteger(uint256.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false)),
                proofOfStakeLimitV2: new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false)),
                proofOfStakeReward: Money.Zero
            );
            
            this.Base58Prefixes[(int) Base58Type.PUBKEY_ADDRESS] = new byte[] {66};
            this.Base58Prefixes[(int) Base58Type.SCRIPT_ADDRESS] = new byte[] {128};
            this.Base58Prefixes[(int) Base58Type.SECRET_KEY] = new byte[] {66 + 128};

            this.Checkpoints = new Dictionary<int, CheckpointInfo>();
            // TODO: Add genesis and premine block to Checkpoints
            // First parameter - block height
            // { 0, new CheckpointInfo(new uint256("0x00000e246d7b73b88c9ab55f2e5e94d9e22d471def3df5ea448f5576b1d156b9"), new uint256("0x0000000000000000000000000000000000000000000000000000000000000000")) },

            var encoder = new Bech32Encoder("bc");
            this.Bech32Encoders = new Bech32Encoder[2];
            this.Bech32Encoders[(int) Bech32Type.WITNESS_PUBKEY_ADDRESS] = encoder;
            this.Bech32Encoders[(int) Bech32Type.WITNESS_SCRIPT_ADDRESS] = encoder;
           
            this.DNSSeeds = new List<DNSSeedData>
            {
//                new DNSSeedData("testnode1.destream.io", "testnode1.destream.io")
            };

            this.SeedNodes = new List<NetworkAddress>();

            this.DeStreamWallets = new LinkedList<string>(new[]
            {
                "TxLYmDJc9bdYLrcT8v3DhUQFD7vnd7hq5n",
                "Ti4QCbGneeaYstSzy1Ak5c9QaWo7sHGznc",
                "Tk4sxrgogk6SE2kPXzCugkEyc9K4dsQPos",
                "TuBB9EEL7EoyWENdk81NuNWKqhpzRK4c4f",
                "Tkn6StGnSoSmtMcVEc2AXf31L6fht6KbHR",
                "TshSmiSkGXzXHdDdMPHYbRpaSR9fKxW1zD",
                "Tm9DdZE7rjyjHpyLWn8rLviP5vcYUdFTuC",
                "TZWfMcNZsJE76LqVxJUu7x3GhxN5ZJ9Uab",
                "TcNV9kvXjHzzu321GZNsusnxds1xoduDhG",
                "TggdqV7oMwcG2ad3xj4TyFMuGYqA8skCAN",
                "TmxHkKHfoEWiJhWyMgoyTfMPFK3vPvAbXi",
                "Tp3kjf2YmcVjJfpMR2VveS7T3kzazHNnkg",
                "TixpciA2nv2t8msRdYDSkTibL34EjKSFXZ",
                "TgySERJHqzEiwqnessVVBLY9NY8PwqvWHK",
                "Th2qkyYrqY5ZrSEzsZ4K1KqYtHfjnXeAJY",
                "TfLnAv1UqF672dkfftAVhxfuZLdeVnZ6nZ",
                "TsWPtxeTpDSoAp1pQfDzpeJegQMiwtxfw6",
                "TffHpyMjrNNxez37QUzDuMmwa4MrZmxWWR",
                "ThRCqMSWZmp5VWVzob1pfjqje6SqosP8Uw",
                "TxMpDfwHb5SZ9fzNMmeLthTd1D4BZ1EGyQ"
            }.OrderBy(p => Guid.NewGuid()));
            
            Assert(this.Consensus.HashGenesisBlock ==
                   uint256.Parse("7882881de9a12aef120d13a660d6bb0075fbf305208a01ac6548d11caea8125a"));
            Assert(this.Genesis.Header.HashMerkleRoot ==
                   uint256.Parse("17ba0a15112b8149c485827f5a2dbbf87a60d8c9bb0d29ffe52fbf762e3ef2ec"));
        }
    }
}