using Minesweeper.Commands;
using Minesweeper.Config;
using Minesweeper.Core;
using Minesweeper.Presentation.ReadModels;
using Minesweeper.Presentation.Views;

namespace Minesweeper.Presentation.Presenters
{
    public sealed class TopPanelPresenter : IPresenter
    {
        private readonly IGameCommandDispatcher commandDispatcher;
        private readonly IGamePauseService pauseService;
        private readonly IGameReadModel readModel;
        private readonly IGameStateService gameStateService;
        private readonly IGameTimerService timerService;
        private readonly ITopPanelView view;

        public TopPanelPresenter(IGameCommandDispatcher commandDispatcher, IGamePauseService pauseService, IGameReadModel readModel, IGameStateService gameStateService, IGameTimerService timerService, ITopPanelView view)
        {
            this.commandDispatcher = commandDispatcher;
            this.pauseService = pauseService;
            this.readModel = readModel;
            this.gameStateService = gameStateService;
            this.timerService = timerService;
            this.view = view;
        }

        public void Initialize()
        {
            view.SmileClicked += OnSmileClicked;
            gameStateService.StateChanged += OnStateChanged;
            pauseService.PauseChanged += OnPauseChanged;
            timerService.TimeChanged += OnTimeChanged;

            RefreshAll();
        }

        public void Dispose()
        {
            view.SmileClicked -= OnSmileClicked;
            gameStateService.StateChanged -= OnStateChanged;
            pauseService.PauseChanged -= OnPauseChanged;
            timerService.TimeChanged -= OnTimeChanged;
        }

        public void RefreshCounters()
        {
            view.SetRemainingMines(readModel.RemainingMinesCount);
        }

        public void SetCellPressActive(bool active)
        {
            var state = gameStateService.Current;
            if (active && !pauseService.IsPaused && (state == GameState.Preparing || state == GameState.Playing))
            {
                view.SetSmile(SmileFaceState.Surprised);
                return;
            }

            view.SetSmile(GetSmileState(state));
        }

        private void RefreshAll()
        {
            view.SetActive(true);
            view.SetRemainingMines(readModel.RemainingMinesCount);
            view.SetTimer(timerService.ElapsedSeconds);
            view.SetSmile(GetSmileState(gameStateService.Current));
        }

        private void OnSmileClicked()
        {
            var state = gameStateService.Current;
            if (state == GameState.FieldSelection)
            {
                commandDispatcher.Dispatch(new StartGameCommand());
            }
            else if (state == GameState.Playing && !pauseService.IsPaused)
            {
                commandDispatcher.Dispatch(new PauseCommand());
            }
            else if (state == GameState.Playing && pauseService.IsPaused)
            {
                commandDispatcher.Dispatch(new ResumeCommand());
            }
            else
            {
                commandDispatcher.Dispatch(new RestartCommand());
            }

            RefreshAll();
        }

        private void OnStateChanged(GameState state)
        {
            if (state == GameState.FieldSelection || state == GameState.Preparing)
            {
                view.SetTimer(0f);
            }

            view.SetSmile(GetSmileState(state));
            view.SetRemainingMines(readModel.RemainingMinesCount);
        }

        private void OnPauseChanged(bool isPaused)
        {
            view.SetSmile(GetSmileState(gameStateService.Current));
        }

        private void OnTimeChanged(float seconds)
        {
            view.SetTimer(seconds);
        }

        private SmileFaceState GetSmileState(GameState state)
        {
            if (state == GameState.Won)
            {
                return SmileFaceState.Cool;
            }

            if (state == GameState.Lost)
            {
                return SmileFaceState.Dead;
            }

            return SmileFaceState.Smile;
        }
    }
}
