using Code;
using Code.Core;

namespace UnitTests;

public class ProjectClassTests
{
    
    // 1. projektu se da ima, eventualno opis i ostale informacije recimo datum početka
    // 2. projektu se dodaju zadaci iz bekloga, tako da se napuni zadacima i spreman je za sprint
    // 3. projektu se otvori prvi sprint, u sprint se upiše datum početka, upiše se broj sprinta
    // 4. nakon toga aktivnom sprintu mogu da se dodele user stories.

    [Test]
    public void StartProjectWithoutStoriesInBacklog_ShouldThrowException()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        var expectedException = Assert.Throws<InvalidOperationException>(() => project.Start());
        Assert.That(expectedException.Message, Is.EqualTo("Project must contain at least one task in backlog to be started."));
    }
    
    [Test]
    public void AssignStoryToCurrentSprint_WhenStoryExistsInBacklog_ShouldRemoveStoryFromBacklog()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        project.AddToBacklog(story);
        project.Start(); //projkat zapocet - ali i pre toga mogu da se dodaju taskovi u backlog
        project.AssignStoryToCurrentSprint(story); //medjutim assignStory ne moze pre zvanicnog starovanja projekta
        Assert.That(project.Backlog.Any(x => x.Title == story.Title), Is.False);
    }
    
    [Test]
    public void AssignStoryToCurrentSprint_WhenStoryExistsInBacklog_ShouldAddStoryToActiveSprint()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        project.AddToBacklog(story);
        project.Start();
        project.AssignStoryToCurrentSprint(story);
        var activeSprint = project.Sprints.Single(x => x.IsActive);
        Assert.That(activeSprint.UserStories.Any(x => x.Title == story.Title), Is.True);
    }
    
    [Test]
    public void Project_EndSprint_IfNoSprintsExceptionMustBeThrown()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        
        var expectedException = Assert.Throws<InvalidOperationException>(() => project.EndSprint());
        Assert.That(expectedException.Message, Is.EqualTo("No sprints to be ended."));
    }
    
    [Test]
    public void Project_EndSprint_WhenEndingOldSprintOldMustBeInactiveAndNewOneMustBeCreatedAndActivated()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        project.AddToBacklog(story);
        project.Start();
        project.AssignStoryToCurrentSprint(story);
        project.EndSprint();
        project.AddToBacklog(story);
        project.AssignStoryToCurrentSprint(story);

        foreach(var sprint in project.Sprints)
            Console.WriteLine(sprint.IsActive + "  " + sprint.SprintNumber);
        Assert.That(project.Sprints.Count, Is.EqualTo(2));
        Assert.That(project.Sprints[1].IsActive, Is.True);
    }

    [Test]
    public void ShouldThrowExceptionIfUserTryToEndEndedSprint()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        var expectedException = Assert.Throws<InvalidOperationException>(() => project.EndSprint());
        Assert.That(expectedException.Message, Is.EqualTo("No sprints to be ended."));
    }

    [Test]
    public void EndProject_WhenNoAvailableStoriesNewSprintShouldNotBeStarted()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        story.IsComplete = true;
        project.AddToBacklog(story);
        // project.CreateNewSprint() //cant access to this method so test passes
        Assert.Pass();
    }

    public void WhenOneSprintEndsAnotherAutomaticlyStarts()
    {
        // var (project, story) = SetProjectAndStoryHelperMethod();
    }
    
    [Test]
    public void StartProject_ShouldCreateFirstActiveSprint()
    {
        var (project, story) = SetProjectAndStoryHelperMethod();
        project.AddToBacklog(story);
        project.Start();

        // Assert
        Assert.That(project.Sprints.Count, Is.EqualTo(1));
        Assert.That(project.Sprints[0].SprintNumber, Is.EqualTo(1));
        Assert.That(project.Sprints[0].IsActive, Is.True);
    }
    
    [Test]
    public void StartProject_WhenProjectAlreadyHasActiveSprint_ShouldThrowException()
    {
        // Arrange
        var (project, _) = SetProjectAndStoryHelperMethod();
        project.AddToBacklog(new UserStory() {Title = "Create project dashboard"});
        project.Start();

        // Act + Assert
        var exception = Assert.Throws<InvalidOperationException>(() => project.Start());
        Assert.That(exception!.Message, Does.Contain("Project already started and has active sprint."));
    }
    
    public (Project, UserStory) SetProjectAndStoryHelperMethod()
    {
        // Arrange
        var project = new Project(
            name: "My Platform",
            description: "Test project",
            sourceCodeRootPath: "/src");

        var story = new UserStory
        {
            Title = "Create project dashboard"
        };
        
        return (project, story);
    }
}