using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NBitcoin;
using Stratis.Bitcoin.Configuration;
using Stratis.Bitcoin.Utilities;
using Transaction = DBreeze.Transactions.Transaction;

namespace Stratis.Bitcoin.Features.Consensus.CoinViews
{
    /// <inheritdoc cref="DBreezeCoinView" />
    public class DeStreamDBreezeCoinView : DBreezeCoinView, IDisposable
    {
        public DeStreamDBreezeCoinView(Network network, DataFolder dataFolder, IDateTimeProvider dateTimeProvider,
            ILoggerFactory loggerFactory, INodeStats nodeStats, DBreezeSerializer dBreezeSerializer) : base(network,
            dataFolder, dateTimeProvider, loggerFactory, nodeStats, dBreezeSerializer)
        {
        }

        public DeStreamDBreezeCoinView(Network network, string folder, IDateTimeProvider dateTimeProvider,
            ILoggerFactory loggerFactory, INodeStats nodeStats, DBreezeSerializer dBreezeSerializer) : base(network,
            folder, dateTimeProvider, loggerFactory, nodeStats, dBreezeSerializer)
        {
        }

        /// <inheritdoc />
        // Instead of ignoring genesis coins, add them to database
        public override Task InitializeAsync()
        {
            Block genesis = this.network.GetGenesis();

            Task task = Task.Run(() =>
            {
                using (Transaction transaction = CreateTransaction())
                {
                    transaction.ValuesLazyLoadingIsOn = false;
                    transaction.SynchronizeTables("BlockHash");

                    if (GetTipHash(transaction) != null) return;
                    SetBlockHash(transaction, genesis.GetHash());

                    // Genesis coin is spendable and added to the database.
                    foreach (UnspentOutputs unspentOutput in
                        genesis.Transactions.Select(p => new UnspentOutputs(0, p)))
                        transaction.Insert("Coins", unspentOutput.TransactionId.ToBytes(false),
                            this.dBreezeSerializer.Serialize(unspentOutput.ToCoins()));

                    transaction.Commit();
                }
            });

            return task;
        }
    }
}