using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Utility;

public partial class GameManager : MonoBehaviourSingleton<GameManager>
{
    [SerializeField] private Difficulty _difficulty = Difficulty.Medium; 
    
    [SerializeField]
    private double _totalGameDurationSeconds;
    
    [SerializeField]
    private double _remainingGameDurationSeconds = 0.0;

    [SerializeField, ShowOnly]
    private double _currentEfficiency = 0.0;
    
    [SerializeField]
    private List<Developer> _developers = new();

    [SerializeField]
    private MultiFalsableBool _gameRunning = new(false);
    
    public Difficulty Difficulty => _difficulty;
    
    /// <summary>
    /// Wie weit das Spiel bereits fortgeschritten ist.
    /// </summary>
    public double GameProgress => 1.0 - (_remainingGameDurationSeconds / _totalGameDurationSeconds);
    
    /// <summary>
    /// Wie Effizient das Team derzeit arbeitet.
    /// </summary>
    public double CurrentEfficiency => _currentEfficiency;
    
    /// <summary>
    /// Wie viele Sekunden das Spiel voraussichtlich noch dauern wird, würde die Effizienz sich nicht verändern.
    /// </summary>
    public double ExpectedRemainingGameDuration => _remainingGameDurationSeconds / _currentEfficiency;

    public bool IsGameRunning => _gameRunning.IsTrue;
    
    private void Start()
    {
        StartGame();
    }


    /// <summary>
    /// Startet ein neues Spiel.
    /// </summary>
    [ContextMenu("Start Game")]
    private void StartGame()
    {
        TimeManager.Instance.Init();

        _totalGameDurationSeconds = TimeManager.Instance.CalculateActualDeveloperTime(_difficulty, 4);

        _remainingGameDurationSeconds = _totalGameDurationSeconds;
        
        ResumeGame();   
    }

    /// <summary>
    /// Hebt eine Pausierung auf und setzt das Spiel fort, wenn alle Pausierungen aufgehoben wurden.
    /// </summary>
    /// <remarks>Hinweis: Für jedes PauseGame muss ein ResumeGame aufgerufen werden.</remarks>
    [ContextMenu("Resume Game")]
    public void ResumeGame()
    {
        if (_gameRunning.MakeTruer())
        {
            InvokeRepeating(nameof(UpdateProgress), 0.0f, 1.0f);    
        }
    }

    /// <summary>
    /// Pausiert das Spiel. Ist Stapelbar.
    /// </summary>
    /// <remarks>Hinweis: Für jedes PauseGame muss ein ResumeGame aufgerufen werden.</remarks>
    [ContextMenu("Pause Game")]
    public void PauseGame()
    {
        _gameRunning.MakeFalslier();
        CancelInvoke(nameof(UpdateProgress));
    }
    
    void UpdateProgress()
    {
        UpdateEfficiency();
        UpdateGameDuration();
        CheckGameEndConditions();
    }

    private void CheckGameEndConditions()
    {
        if (_remainingGameDurationSeconds <= 0.0)
        {
            EndGame(EndGameCondition.Win_GamePublished);
        }
        else if (_developers.Count == 0)
        {
            EndGame(EndGameCondition.Lose_NoDevelopersLeft);
        }
        else if (TimeManager.Instance.MissedDeadline)
        {
            EndGame(EndGameCondition.Lose_DeadlineMissed);
        }
    }

    private void EndGame(EndGameCondition endGameCondition)
    {
        if (endGameCondition.IsWin())
        {
            Debug.Log("You won!");
        }
        else if (endGameCondition.IsLose())
        {
            Debug.Log("You lost!");
        }
        
        Debug.Log(endGameCondition.GetEndGameMessage());
        
        PauseGame();
    }
    
    void UpdateEfficiency()
    {
        double developerEfficiency = 0.0f;
        
        foreach (Developer developer in _developers)
        {
            developer.UpdateEfficiency();
            developerEfficiency += developer.CurrentEfficiency;
        }
        
        _currentEfficiency = developerEfficiency;
    }

    void UpdateGameDuration()
    {
        // Entwickler Effizienz ist im Grunde wie viele Entwicklersekunden wir pro Sekunde verrichten können.
        _remainingGameDurationSeconds -= _currentEfficiency;
    }
}
