using Common.Library;
using CommunityToolkit.Maui;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using GreadyPoang.DataLayer;
using GreadyPoang.EntityLayer;
using GreadyPoang.Services;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;

namespace GreadyPoang.ViewModelLayer;

public partial class RoundRunningViewModel : ObservableObject
{

    public event EventHandler RebuildRequested;
    public ICommand OnLoadedCommand { get; }

    public RoundRunningViewModel() : base()
    {
    }

    public RoundRunningViewModel(

        IRepository<GameRound> roundsRepo,
        IRepository<GamePoint> pointsRepo,
        IMethodSharingService<Participant> sharingService,
        ICombinedRepository combined,
        IObjectMessageService objectMessage,
        IPopupService popupService,
        IPopupEventHub popupEvent
        ) : base()
    {
        _roundsRepo = roundsRepo;
        _pointsRepo = pointsRepo;
        _sharingService = sharingService;
        _combined = combined;
        _objectMessage = objectMessage;
        _popupService = popupService;
        _popupEvent = popupEvent;
        RoundElements = new ObservableCollection<RoundBuilderElement>();
        BuilderObject = new();
        _popupEvent.InfoPopupCloseRequested += infoPopupViewModel_ClosePopupRequested;
        PopupVisad = false;
        OnLoadedCommand = new AsyncRelayCommand(OnLoadedAsync, () => true);

    }

    private readonly IRepository<GameRound>? _roundsRepo;
    private readonly IRepository<GamePoint> _pointsRepo;
    private readonly IMethodSharingService<Participant> _sharingService;
    private readonly ICombinedRepository _combined;
    private readonly IObjectMessageService _objectMessage;
    private readonly IPopupService _popupService;
    private readonly IPopupEventHub _popupEvent;

    [ObservableProperty]
    private ObservableCollection<RoundBuilderElement> roundElements;
    [ObservableProperty]
    private Collection<PlayerColumn> playerColumns;
    [ObservableProperty]
    private RoundBuilderElement builderObject;
    public ObservableCollection<ScoreColumn> ScoreColumns { get; } = new ObservableCollection<ScoreColumn>();



    private string _activePopupId;

    public bool PopupVisad { get; set; }

    private async Task OnLoadedAsync()
    {
        await Get();
    }

    public async Task Get()
    {

        if (_objectMessage.CurrentGroup != null)
        {
            //CurrentGroup är satt från RoundStarting ViewModel
            Debug.WriteLine($"Chosen round: {_objectMessage.CurrentGroup.GameRoundId}");
            if (RoundElements.Count > 0)
            {
                RoundElements.Clear();
            }
            foreach (var item in _objectMessage.CurrentGroup.Elements)
            {
                RoundElements.Add(item);
            }

            // Räkna ut vem som är nästa spelare
            var nxt = nextPlayerElement();

            // Aktuell spelare sätts som BuilderObject
            BuilderObject.ParticipantName = _objectMessage.CurrentGroup.Elements[nxt].ParticipantName;
            BuilderObject.GameRoundId = _objectMessage.CurrentGroup.GameRoundId;
            BuilderObject.ParticipantId = _objectMessage.CurrentGroup.Elements[nxt].ParticipantId;
            BuilderObject.Status = _objectMessage.CurrentGroup.Status;

            // Alla poängposter från samtliga spelare i rundan samlas ihop och fördelas per deltagare
            var localElements = _combined.roundBuilderElementsTotalById(_objectMessage.CurrentGroup.GameRoundId);

            FillupResultTable(localElements);
            foreach (var col in PlayerColumns)
            {
                RoundElements.FirstOrDefault(e => e.ParticipantId == col.PlayerId).GameRegPoints = col.PlayerPoints;
            }
            //TriggerRebuild();
            BuildScore(playerColumns);

        }
    }


    [RelayCommand]
    private void StoreAndHandlePointsAsync()
    {
        var game = _roundsRepo.Get(BuilderObject.GameRoundId).GetAwaiter().GetResult();
        var regNr = RoundElements.Count > 0 ? RoundElements.Max(e => e.GameRoundRegNr) + 1 : 1;

        if (game.GameStatus == GamePointStatus.New)
        {
            game.GameStatus = GamePointStatus.InProgress;
            regNr = regNr == 0 ? 1 : regNr;
            _roundsRepo.Save(game);

        }

        BuilderObject.Status = game.GameStatus;
        var points = BuilderObject.GameRegPoints;
        var newPoint = new GamePoint
        {
            ParticipantId = BuilderObject.ParticipantId,
            GameRoundId = BuilderObject.GameRoundId,
            GameDate = DateTime.Now,
            GameRoundRegNr = regNr,
            GameRegPoints = points
        };
        var pointId = _pointsRepo?.Save(newPoint).GetAwaiter().GetResult();

        // Uppdatera listan med element
        var tmpElements = _combined.roundBuilderElementsDbById(BuilderObject.GameRoundId);
        RoundElements.Clear();
        foreach (var item in tmpElements)
        {
            item.Status = GamePointStatus.InProgress;
            RoundElements.Add(item);
        }

        // Uppdatera spelaren som skall spela nästa
        var nxt = nextPlayerElement();
        BuilderObject.GameRegPoints = 0;
        BuilderObject.ParticipantName = RoundElements[nxt].ParticipantName;
        BuilderObject.ParticipantId = RoundElements[nxt].ParticipantId;
        BuilderObject.GameRoundId = RoundElements[0].GameRoundId;

        var localElements = _combined.roundBuilderElementsTotalById(BuilderObject.GameRoundId);
        FillupResultTable(localElements);
        foreach (var col in PlayerColumns)
        {
            RoundElements.FirstOrDefault(e => e.ParticipantId == col.PlayerId).GameRegPoints = col.PlayerPoints;
        }
        //        TriggerRebuild();
        BuildScore(playerColumns);
        Shell.Current.GoToAsync("..").GetAwaiter().GetResult();

    }

    private int nextPlayerElement()
    {
        for (int i = 0; i < RoundElements.Count; i++)
        {
            if (RoundElements[i].GameRoundRegNr == -1 ||
               (i > 0 && (RoundElements[i - 1].GameRoundRegNr > RoundElements[i].GameRoundRegNr)) ||
                   (i == 0 && RoundElements[i].GameRoundRegNr < RoundElements[RoundElements.Count - 1].GameRoundRegNr))
                return i;
        }
        return -1;
    }

    private void Show_a_Popup(string ppName, string ppTitle, string ppMessage)
    {
        if (!PopupVisad)
        {
            var queryAttributes = new Dictionary<string, object>
            {
                [nameof(InfoPopupViewModel.Title)] = ppTitle,
                [nameof(InfoPopupViewModel.Message)] = ppMessage,
                [nameof(InfoPopupViewModel.Name)] = ppName,

            };

            _popupService.ShowPopup<InfoPopupViewModel>(
                Shell.Current,
                options: PopupOptions.Empty,
                shellParameters: queryAttributes);

            _activePopupId = LatestPopup.valueGuid;

        }
    }

    private async void infoPopupViewModel_ClosePopupRequested(object? sender, PopupCloseEventArgs e)
    {
        if (e.PopupId != _activePopupId)
        {
            return;
        }
        PopupVisad = true;
        await _popupService.ClosePopupAsync(Shell.Current);
    }


    private void FillupResultTable(IEnumerable<RoundBuilderElement> elements)
    {
        if (PlayerColumns != null)
        {
            PlayerColumns.Clear();
        }
        else
        {
            PlayerColumns = new Collection<PlayerColumn>();
        }

        //        if (elements.Any(g => g.GameRegPoints > 0))
        if (BuilderObject.Status == GamePointStatus.InProgress)
        {
            PlayerColumn player = new PlayerColumn();

            foreach (var element in elements)
            {
                player = PlayerColumns.FirstOrDefault(p => p.PlayerId == element.ParticipantId);

                if (player == null)
                {
                    player = new PlayerColumn
                    {
                        PlayerName = element.ParticipantName,
                        PlayerId = element.ParticipantId,
                        PlayerPoints = 0
                    };
                }

                if (element.GameRegPoints > 0)
                {
                    player.Values.Add(element.GameRegPoints.ToString());
                    var playerPointsOld = player.PlayerPoints;
                    player.PlayerPoints += element.GameRegPoints;
                    if (player.PlayerPoints > 10000)
                    {
                        var winner = RoundElements.FirstOrDefault(e => e.ParticipantId == player.PlayerId);
                        var oldStatus = winner.Status;
                        winner.Status = GamePointStatus.Winning;
                        if (playerPointsOld < 10000 && oldStatus != winner.Status)
                        {
                            Show_a_Popup(
                            player.PlayerName,
                            "Se upp för denne spelare !",
                            $"Du har nått en poängnivå över 10000 ({player.PlayerPoints})\r" +
                            $"Alla övriga får nu en chans att överträffa\r" +
                            $"om någon kommer till samma poäng som\r" +
                            $"{player.PlayerName}\r" +
                            $"får hen försvara sig med nytt kast\r" +
                            $"Om kastet inte blir godkänt (ger poäng)\r" +
                            $"Vinner den upphinnande spelaren"
                            );
                        }
                    }
                }

                if (!PlayerColumns.Contains(player))
                {
                    PlayerColumns.Add(player);
                }
            }
        }
        else
        {
            Random slumper = new Random();

            foreach (var element in elements)
            {
                var player = new PlayerColumn
                {
                    PlayerName = element.ParticipantName,
                    PlayerId = element.ParticipantId,
                    PlayerPoints = 0
                };

                for (int i = 0; i < slumper.Next(6); i++)
                {
                    player.Values.Add(slumper.Next(1, 10).ToString());
                }

                PlayerColumns.Add(player);
            }
        }
    }


    public void BuildScore(IEnumerable<PlayerColumn> columns)
    {
        ScoreColumns.Clear();


        foreach (var column in columns)
        {
            var scoreColumn = new ScoreColumn
            {
                PlayerName = column.PlayerName
            };

            scoreColumn.Cells.Add(new ScoreCell
            {
                Text = column.PlayerName,
                IsHeader = true
            });

            foreach (var value in System.Linq.Enumerable.Reverse(column.Values))
            {
                scoreColumn.Cells.Add(new ScoreCell
                {
                    Text = value,
                    IsHeader = false
                });
            }

            ScoreColumns.Add(scoreColumn);
        }
    }

}


