package story_service_test

import (
	"evening_detective/internal/modules/cleaner"
	"evening_detective/internal/modules/formatter"
	"evening_detective/internal/services/link"
	"evening_detective/internal/services/story_service"
	"evening_detective/internal/services/story_service/models"
	"evening_detective/internal/services/story_storage"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestStoryService_GetPlace(t *testing.T) {
	tests := []struct {
		name  string
		story *models.Story
		code  string
		want  *models.Place
	}{
		{
			name:  "не корректный ввода",
			story: &models.Story{},
			code:  "[Ы]",
			want:  models.NewClientErrorPlace("[Ы]"),
		},
		{
			name:  "точка не найдена",
			story: &models.Story{},
			code:  "Ы",
			want:  models.NewNotFoundPlace("Ы"),
		},
		{
			name: "получение точки",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace("Ы", "Название", "Текст"),
				},
			},
			code: "Ы",
			want: models.NewPlace("Ы", "Название", "Текст"),
		},
		{
			name: "получение скрытой точки",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
				},
			},
			code: "Ы",
			want: models.NewPlace(
				"Ы",
				"Название",
				"Текст",
				models.WithPlaceHidden(true),
			),
		},
		{
			name: "получение точки с приложением",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы",
						"Название",
						"Текст",
						models.WithPlaceApplication(
							models.NewApplication("Приложение"),
						),
					),
				},
			},
			code: "Ы",
			want: models.NewPlace(
				"Ы",
				"Название",
				"Текст",
				models.WithPlaceApplication(
					models.NewApplication("Приложение"),
				),
			),
		},
		{
			name: "получение точки с проходом",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor("Й", "Приложение"),
						),
					),
				},
			},
			code: "Ы",
			want: models.NewPlace(
				"Ы",
				"Название",
				"Текст",
				models.WithPlaceDoors(
					models.NewDoor("Й", "Приложение"),
				),
			),
		},
		{
			name: "получение точки с диалогом",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor(
								"Й",
								"Приложение",
								models.WithDoorShow(true),
							),
						),
					),
				},
			},
			code: "Ы",
			want: models.NewPlace(
				"Ы",
				"Название",
				"Текст",
				models.WithPlaceDoors(
					models.NewDoor(
						"Й",
						"Приложение",
						models.WithDoorShow(true),
					),
				),
			),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s, err := story_service.NewStoryService(
				cleaner.NewCleaner(),
				formatter.NewFormatter(),
				story_storage.NewVarStoryStorage(tt.story),
				link.NewLinkService("http://localhost:8120"),
			)
			if err != nil {
				t.Fatalf("could not construct receiver type: %v", err)
			}
			got := s.GetPlace(tt.code)
			assert.Equal(t, got, tt.want)
		})
	}
}

func TestStoryService_GetPlaces(t *testing.T) {
	tests := []struct {
		name  string
		story *models.Story
		codes []string
		want  []*models.Place
	}{
		{
			name: "Можно сходить в открытую точку",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace("Ы", "Название", "Текст"),
				},
			},
			codes: []string{"Ы"},
			want: []*models.Place{
				models.NewPlace("Ы", "Название", "Текст"),
			},
		},
		{
			name: "Нельзя открыть скрытую точку",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
				},
			},
			codes: []string{"Ы"},
			want: []*models.Place{
				models.NewNotFoundPlace("Ы"),
			},
		},
		{
			name: "Открываем скрытую точку",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы-1",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor("Ы-2", "Название"),
							models.NewDoor("Ы-3", "Название"),
						),
					),
					models.NewPlace(
						"Ы-2",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
					models.NewPlace(
						"Ы-3",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
				},
			},
			codes: []string{"Ы-1", "Ы-2", "Ы-3"},
			want: []*models.Place{
				models.NewPlace(
					"Ы-1",
					"Название",
					"Текст",
					models.WithPlaceDoors(
						models.NewDoor("Ы-2", "Название"),
						models.NewDoor("Ы-3", "Название"),
					),
				),
				models.NewPlace(
					"Ы-2",
					"Название",
					"Текст",
					models.WithPlaceHidden(true),
				),
				models.NewPlace(
					"Ы-3",
					"Название",
					"Текст",
					models.WithPlaceHidden(true),
				),
			},
		},
		{
			name: "Открываем скрытую точку диалога",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы-1",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
						),
					),
					models.NewPlace(
						"Ы-2",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
					models.NewPlace(
						"Ы-3",
						"Название",
						"Текст",
					),
				},
			},
			codes: []string{"Ы-1", "Ы-3", "Ы-2"},
			want: []*models.Place{
				models.NewPlace(
					"Ы-1",
					"Название",
					"Текст",
					models.WithPlaceDoors(
						models.NewDoor("Ы-2", "Название", models.WithDoorShow(false)),
					),
				),
				models.NewPlace(
					"Ы-3",
					"Название",
					"Текст",
				),
				models.NewNotFoundPlace("Ы-2"),
			},
		},
		{
			name: "Открываем скрытую точку диалога",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы-1",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
							models.NewDoor("Ы-3", "Название", models.WithDoorShow(true)),
						),
					),
					models.NewPlace(
						"Ы-2",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
					models.NewPlace(
						"Ы-3",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
				},
			},
			codes: []string{"Ы-1", "Ы-2", "Ы-3"},
			want: []*models.Place{
				models.NewPlace(
					"Ы-1",
					"Название",
					"Текст",
					models.WithPlaceDoors(
						models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
						models.NewDoor("Ы-3", "Название", models.WithDoorShow(false)),
					),
				),
				models.NewPlace(
					"Ы-2",
					"Название",
					"Текст",
					models.WithPlaceHidden(true),
				),
				models.NewNotFoundPlace("Ы-3"),
			},
		},
		{
			name: "Открываем скрытую точку после диалога",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы-1",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
							models.NewDoor("Ы-3", "Название", models.WithDoorShow(true)),
							models.NewDoor("Ы-4", "Название"),
						),
					),
					models.NewPlace(
						"Ы-2",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
					models.NewPlace(
						"Ы-3",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
					models.NewPlace(
						"Ы-4",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
				},
			},
			codes: []string{"Ы-1", "Ы-2", "Ы-3", "Ы-4"},
			want: []*models.Place{
				models.NewPlace(
					"Ы-1",
					"Название",
					"Текст",
					models.WithPlaceDoors(
						models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
						models.NewDoor("Ы-3", "Название", models.WithDoorShow(false)),
						models.NewDoor("Ы-4", "Название"),
					),
				),
				models.NewPlace(
					"Ы-2",
					"Название",
					"Текст",
					models.WithPlaceHidden(true),
				),
				models.NewNotFoundPlace("Ы-3"),
				models.NewPlace(
					"Ы-4",
					"Название",
					"Текст",
					models.WithPlaceHidden(true),
				),
			},
		},
		{
			name: "Открытие второй раз точки не дает задать другой вопрос",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы-1",
						"Название",
						"Текст",
						models.WithPlaceDoors(
							models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
							models.NewDoor("Ы-3", "Название", models.WithDoorShow(true)),
						),
					),
					models.NewPlace(
						"Ы-2",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
					models.NewPlace(
						"Ы-3",
						"Название",
						"Текст",
						models.WithPlaceHidden(true),
					),
				},
			},
			codes: []string{"Ы-1", "Ы-2", "Ы-3", "Ы-1", "Ы-3", "Ы-2"},
			want: []*models.Place{
				models.NewPlace(
					"Ы-1",
					"Название",
					"Текст",
					models.WithPlaceDoors(
						models.NewDoor("Ы-2", "Название", models.WithDoorShow(true)),
						models.NewDoor("Ы-3", "Название", models.WithDoorShow(false)),
					),
				),
				models.NewPlace(
					"Ы-2",
					"Название",
					"Текст",
					models.WithPlaceHidden(true),
				),
				models.NewNotFoundPlace("Ы-3"),
				models.NewPlace(
					"Ы-1",
					"Название",
					"Текст",
					models.WithPlaceDoors(
						models.NewDoor("Ы-2", "Название", models.WithDoorShow(false)),
						models.NewDoor("Ы-3", "Название", models.WithDoorShow(false)),
					),
				),
				models.NewNotFoundPlace("Ы-3"),
				models.NewNotFoundPlace("Ы-2"),
			},
		},
		{
			name: "Улики не повторяются",
			story: &models.Story{
				Places: []*models.Place{
					models.NewPlace(
						"Ы",
						"Название",
						"Текст",
						models.WithPlaceApplication(
							models.NewApplication("Название"),
						),
					),
				},
			},
			codes: []string{"Ы", "Ы"},
			want: []*models.Place{
				models.NewPlace(
					"Ы",
					"Название",
					"Текст",
					models.WithPlaceApplication(
						models.NewApplication(
							"Название",
							models.WithApplicationNumber(1),
						),
					),
				),
				models.NewPlace(
					"Ы",
					"Название",
					"Текст",
				),
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s, err := story_service.NewStoryService(
				cleaner.NewCleaner(),
				formatter.NewFormatter(),
				story_storage.NewVarStoryStorage(tt.story),
				link.NewLinkService("http://localhost:8120"),
			)
			assert.Nil(t, err)

			got := s.GetPlaces(tt.codes)
			assert.Equal(t, got, tt.want)
		})
	}
}
