namespace Code.Core;

public class Project
{
    public List<string> EventsInOrder { get; set; } = new();
    public string Name { get; private set; }
    public string Description { get; private set; }
    public string SourceCodeRootPath { get; private set; }
    public DateTime OpeningDate { get; private set; }
    public DateTime StartingDate {get; private set;}
    public DateTime EndDate {get; private set;}
    public List<UserStory> Backlog { get; private set; } = new();
    public List<Sprint> Sprints { get; private set; } = new();
    public Project(string name, string description, string sourceCodeRootPath)
    {
        this.Name = name;
        this.Description = description;
        this.SourceCodeRootPath = sourceCodeRootPath;
        this.OpeningDate = DateTime.Now;
    }
    
    public void DefineBasicData()
    {
        EventsInOrder.Add("Basic Data Saved " + this.Name + " " + this.Description);
    }

    public void AddToBacklog(UserStory userStory)
    {
        ArgumentNullException.ThrowIfNull(userStory);

        if (Backlog.Any(x => x.Title == userStory.Title))
        {
            throw new InvalidOperationException("Story already exists in backlog.");
        }
        
        this.Backlog.Add(userStory);
        EventsInOrder.Add("Added story to backlog " + userStory + " in " + this.Backlog.ToString());
    }
    
    public void Start()
    {
        if(Sprints.Any(x => x.IsActive == true))
            throw new InvalidOperationException("Project already started and has active sprint.");
        
        CreateNewSprint();
        if (Sprints.Count == 0)
            throw new InvalidOperationException("Project without at least one sprint cannot be started.");

        if(Backlog.Count == 0)
            throw new InvalidOperationException("Project must contain at least one task in backlog to be started.");
        
        Sprints.First().IsActive = true;
    }

    public void EndSprint()
    {
        if (Sprints.Count == 0)
            throw new InvalidOperationException("No sprints to be ended.");
        
        var oldSprint = Sprints.First(x => x.IsActive);
        oldSprint.IsActive = false;
        var newSprintNumber = Sprints.Count();
        CreateNewSprint(newSprintNumber);
    }
    
    private void CreateNewSprint(int sprintNumber = 1)
    {
        Sprints.Add(new Sprint()
        {
            SprintNumber = sprintNumber,
            StartDate = DateTime.Now,
            EndDate = new DateTime(),
            IsActive = true
        });
    }

    public void AssignStoryToCurrentSprint(UserStory story)
    {
        if (Sprints.Count == 0 || !Sprints.Any(x => x.IsActive))
            throw new InvalidOperationException("There is no active sprint, so that story can't be assigned. Call Start method first.");

        if (Backlog.All(x => x.Title != story.Title))
            throw new InvalidOperationException("Story not found in backlog, cannot assign story to current sprint as it is not found in backlog. Call AddToBacklog method first.");
        
        Backlog.Remove(Backlog.First(x => x.Title == story.Title));
        Sprints.First(x => x.IsActive==true).UserStories.Add(story);
        
        //when you assign your first story to current sprint we count your project started
        if (Sprints.Count == 1)
            this.OpeningDate = DateTime.Now;
    }
}