package accounting

import (
	"encoding/json"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/c9s/bbgo/pkg/fixedpoint"
	"github.com/c9s/bbgo/pkg/types"
)

func TestStockManager(t *testing.T) {

	t.Run("testdata", func(t *testing.T) {
		var trades []types.Trade

		out, err := os.ReadFile("testdata/btcusdt-trades.json")
		assert.NoError(t, err)

		err = json.Unmarshal(out, &trades)
		assert.NoError(t, err)

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err = stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Equal(t, "0.72970242", stockManager.Stocks.Quantity().String())
		assert.NotEmpty(t, stockManager.Stocks)
		assert.Equal(t, 20, len(stockManager.Stocks))
		assert.Equal(t, 0, len(stockManager.PendingSells))

	})

	t.Run("stock", func(t *testing.T) {
		var trades = []types.Trade{
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.01"), IsBuyer: false},
		}

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err := stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Len(t, stockManager.Stocks, 2)
		assert.Equal(t, StockSlice{
			{
				Symbol:   "BTCUSDT",
				Price:    fixedpoint.MustNewFromString("9100.0"),
				Quantity: fixedpoint.MustNewFromString("0.05"),
				IsBuyer:  true,
			},
			{
				Symbol:   "BTCUSDT",
				Price:    fixedpoint.MustNewFromString("9100.0"),
				Quantity: fixedpoint.MustNewFromString("0.04"),
				IsBuyer:  true,
			},
		}, stockManager.Stocks)
		assert.Len(t, stockManager.PendingSells, 0)
	})

	t.Run("sold out", func(t *testing.T) {
		var trades = []types.Trade{
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
		}

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err := stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Len(t, stockManager.Stocks, 0)
		assert.Len(t, stockManager.PendingSells, 0)
	})

	t.Run("oversell", func(t *testing.T) {
		var trades = []types.Trade{
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
		}

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err := stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Len(t, stockManager.Stocks, 0)
		assert.Len(t, stockManager.PendingSells, 1)
	})

	t.Run("loss sell", func(t *testing.T) {
		var trades = []types.Trade{
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.02"), IsBuyer: false},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("8000.0"), Quantity: fixedpoint.MustNewFromString("0.01"), IsBuyer: false},
		}

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err := stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Len(t, stockManager.Stocks, 1)
		assert.Equal(t, StockSlice{
			{
				Symbol:   "BTCUSDT",
				Price:    fixedpoint.MustNewFromString("9100.0"),
				Quantity: fixedpoint.MustNewFromString("0.02"),
				IsBuyer:  true,
			},
		}, stockManager.Stocks)
		assert.Len(t, stockManager.PendingSells, 0)
	})

	t.Run("pending sell 1", func(t *testing.T) {
		var trades = []types.Trade{
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.02")},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
		}

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err := stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Len(t, stockManager.Stocks, 1)
		assert.Equal(t, StockSlice{
			{
				Symbol:   "BTCUSDT",
				Price:    fixedpoint.MustNewFromString("9100.0"),
				Quantity: fixedpoint.MustNewFromString("0.03"),
				IsBuyer:  true,
			},
		}, stockManager.Stocks)
		assert.Len(t, stockManager.PendingSells, 0)
	})

	t.Run("pending sell 2", func(t *testing.T) {
		var trades = []types.Trade{
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.1")},
			{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
		}

		var stockManager = &StockDistribution{
			TradingFeeCurrency: "BNB",
			Symbol:             "BTCUSDT",
		}

		_, err := stockManager.AddTrades(trades)
		assert.NoError(t, err)
		assert.Len(t, stockManager.Stocks, 0)
		assert.Len(t, stockManager.PendingSells, 1)
		assert.Equal(t, StockSlice{
			{
				Symbol:   "BTCUSDT",
				Price:    fixedpoint.MustNewFromString("9200.0"),
				Quantity: fixedpoint.MustNewFromString("0.05"),
				IsBuyer:  false,
			},
		}, stockManager.PendingSells)
	})

}
