using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Should;
using WebApiBook.IssueTrackerApi.Models;
using Xbehave;

namespace WebApiBook.IssueTrackerApp.AcceptanceTests.Features
{
    public class ProcessingIssues : IssuesFeature
    {
        private readonly string _uriProcessor = "http://localhost/issueprocessor/1?";

        [Scenario]
        public void ClosingAnOpenIssue(Issue issue)
        {
            "Mając istniejące otwarte zgłoszenie błędu".
                f(() =>
                {
                    issue = FakeIssues.FirstOrDefault(i => i.Status == IssueStatus.Open);
                    MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult(issue));
                    MockIssueStore.Setup(i => i.UpdateAsync(issue)).Returns(Task.FromResult(""));
                });
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'close'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=close");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '200 OK'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.OK));
            "Wtedy zgłoszenie błędu będzie zamknięte".
                f(() =>
                {
                    issue.Status.ShouldEqual(IssueStatus.Closed);
                    MockIssueStore.Verify(i => i.UpdateAsync(issue));
                });
        }

        [Scenario]
        public void TransitioningAnOpenIssue(Issue issue)
        {
            "Mając istniejące otwarte zgłoszenie błędu".
                f(() =>
                {
                    issue = FakeIssues.FirstOrDefault(i => i.Status == IssueStatus.Open);
                    MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult(issue));
                    MockIssueStore.Setup(i => i.UpdateAsync(issue)).Returns(Task.FromResult(""));
                });
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'transition'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=transition");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '200 OK'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.OK));
            "Wtedy zgłoszenie błędu będzie zamknięte".
                f(() =>
                {
                    issue.Status.ShouldEqual(IssueStatus.Closed);
                    MockIssueStore.Verify(i => i.UpdateAsync(issue));
                });
        }

        [Scenario]
        public void ClosingAClosedIssue(Issue issue)
        {
            "Mając istniejące zamknięte zgłoszenie błędu".
                f(() =>
                {
                    issue = FakeIssues.FirstOrDefault(i => i.Status == IssueStatus.Closed);
                    MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult(issue));
                    MockIssueStore.Setup(i => i.UpdateAsync(issue)).Returns(Task.FromResult(""));
                });
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'close'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=close");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '200 OK'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.BadRequest));
        }

        [Scenario]
        public void OpeningAClosedIssue(Issue issue)
        {
            "Mając istniejące zamknięte zgłoszenie błędu".
                 f(() =>
                {
                    issue = FakeIssues.FirstOrDefault(i => i.Status == IssueStatus.Closed);
                    MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult(issue));
                    MockIssueStore.Setup(i => i.UpdateAsync(issue)).Returns(Task.FromResult(""));
                });
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'open'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=open");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '200 OK'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.OK));
            "Wtedy zgłoszenie błędu będzie zamknięte".
                f(() =>
                {
                    issue.Status.ShouldEqual(IssueStatus.Open);
                    MockIssueStore.Verify(i => i.UpdateAsync(issue));
                });
        }

        [Scenario]
        public void TransitioningAClosedIssue(Issue issue)
        {
            "Mając istniejące zamknięte zgłoszenie błędu".
                f(() =>
                {
                    issue = FakeIssues.FirstOrDefault(i => i.Status == IssueStatus.Closed);
                    MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult(issue));
                    MockIssueStore.Setup(i => i.UpdateAsync(issue)).Returns(Task.FromResult(""));
                });
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'open'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=open");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '200 OK'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.OK));
            "Wtedy zgłoszenie błędu będzie zamknięte".
                f(() =>
                {
                    issue.Status.ShouldEqual(IssueStatus.Open);
                    MockIssueStore.Verify(i => i.UpdateAsync(issue));
                });
        }

        [Scenario]
        public void OpeningAnOpenIssue(Issue issue)
        {
            "Mając istniejące otwarte zgłoszenie błędu".
                f(() =>
                {
                    issue = FakeIssues.FirstOrDefault(i => i.Status == IssueStatus.Closed);
                    MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult(issue));
                    MockIssueStore.Setup(i => i.UpdateAsync(issue)).Returns(Task.FromResult(""));
                });
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'open'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=close");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '400 Bad Request'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.BadRequest));
        }

        [Scenario]
        public void OpeningAnIssueThatDoesNotExist()
        {
            "Mając nieistniejące zgłoszenie błędu".
                f(() => MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult((Issue)null)));
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'open'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=open");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '404 Not Found'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.NotFound));
        }

        [Scenario]
        public void ClosingAnIssueThatDoesNotExist()
        {
            "Mając nieistniejące zgłoszenie błędu".
                f(() => MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult((Issue)null)));
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'close'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=close");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '404 Not Found'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.NotFound));
        }

        [Scenario]
        public void TransitioningAnIssueThatDoesNotExist()
        {
            "Mając nieistniejące zgłoszenie błędu".
                f(() => MockIssueStore.Setup(i => i.FindAsync("1")).Returns(Task.FromResult((Issue)null)));
            "Kiedy żądanie POST zostanie wykonane do komponentu przetwarzającego zgłoszenie błędu i akcją jest 'transition'".
                f(() =>
                {
                    Request.RequestUri = new Uri(_uriProcessor + "action=transition");
                    Request.Method = HttpMethod.Post;
                    Response = Client.SendAsync(Request).Result;
                });
            "Wtedy będzie zwrócony kod stanu '404 Not Found'".
                f(() => Response.StatusCode.ShouldEqual(HttpStatusCode.NotFound));
        }
    }
}
