package services

import (
	"58team_blog/internal/application/commands"
	"58team_blog/internal/application/common"
	"58team_blog/internal/application/mapper"
	"58team_blog/internal/application/queries"
	"58team_blog/internal/domain/entities"
	"58team_blog/internal/domain/repository"
	"errors"
	"fmt"
)

type PostsService struct {
	repo repository.PostsRepository
}

func CreatePostsService(repo repository.PostsRepository) PostsService {
	return PostsService{
		repo: repo,
	}
}

func (s *PostsService) Create(cmd commands.CreatePostsCommand) (*common.PostsResult, error) {
	if user, err := s.repo.FindByPostId(cmd.PostId); user != nil {
		if err != nil {
			return nil, err
		}

		return nil, errors.New("Posts already exists")
	}

	entity, err := entities.CreatePosts(cmd.UserId, cmd.PostId)
	if err != nil {
		return nil, err
	}

	if err := entity.Validate(); err != nil {
		return nil, err
	}

	result := mapper.CreatePostsResultFromEntity(&entity)

	return result, nil
}

func (s *PostsService) FindByUserId(query queries.PostsFindByUserIdQuery) (*queries.PostsFindByUserIdResult, error) {
	entity, err := s.repo.FindByUserId(query.UserId)
	if err != nil {
		return nil, err
	}

	if entity == nil {
		return nil, errors.New("Posts not found")
	}

	if err := entity.Validate(); err != nil {
		return nil, err
	}

	result := mapper.CreatePostsFindByUserIdResultFromEntity(entity)

	return result, nil
}

func (s *PostsService) FindByPostId(query queries.PostsFindByPostIdQuery) (*queries.PostsFindByPostIdResult, error) {
	entity, err := s.repo.FindByPostId(query.PostId)
	if err != nil {
		return nil, err
	}

	if entity == nil {
		return nil, errors.New("Posts not found")
	}

	if err := entity.Validate(); err != nil {
		return nil, err
	}

	result := mapper.CreatePostsFindByPostIdResultFromEntity(entity)

	return result, nil
}

func (s *PostsService) FindAllByUserId(query queries.PostsFindByUserIdQuery) (*queries.PostsFindAllByUserIdResult, error) {
	entities, err := s.repo.FindAllByUserId(query.UserId)
	if err != nil {
		return nil, err
	}

	if entities == nil {
		return nil, fmt.Errorf("No posts owned by user: %s", query.UserId.String())
	}

	for _, e := range entities {
		if err := e.Validate(); err != nil {
			return nil, err
		}
	}

	result := mapper.CreatePostsFindAllByUserIdResultFromEntity(entities)

	return result, nil
}

func (s *PostsService) GetAll() (*queries.PostsGetAllResult, error) {
	entities, err := s.repo.GetAll()
	if err != nil {
		return nil, err
	}

	for _, e := range entities {
		if err := e.Validate(); err != nil {
			return nil, err
		}
	}

	result := mapper.CreatePostsGetAllResultFromEntity(entities)
	return result, nil
}

func (s *PostsService) Delete(cmd commands.DeletePostsCommand) error {
	entity, err := s.repo.FindById(cmd.Id)
	if err != nil {
		return err
	}

	if entity == nil {
		return fmt.Errorf("Posts row not found: %s", cmd.Id)
	}

	if err := entity.Validate(); err != nil {
		return err
	}

	if err := s.repo.Delete(cmd.Id); err != nil {
		return err
	}

	return nil
}
