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"
	"fmt"
	"time"
)

type PostService struct {
	repo repository.PostRepository
}

func CreatePostService(repo repository.PostRepository) PostService {
	return PostService{
		repo: repo,
	}
}

func (s *PostService) Create(cmd commands.CreatePostCommand) (*common.PostResult, error) {
	entity, err := entities.CreatePost(cmd.UserId, cmd.Title, cmd.Description, cmd.Content)
	if err != nil {
		return nil, err
	}

	post, err := s.repo.Create(&entity)
	if err != nil {
		return nil, fmt.Errorf("Db error: %s", err)
	}

	result := mapper.CreatePostResultFromEntity(post)

	return result, nil
}

func (s *PostService) FindById(query queries.PostFindByIdQuery) (*queries.PostFindByIdResult, error) {
	post, err := s.repo.FindById(query.Id)
	if err != nil {
		return nil, err
	}

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

	result := mapper.CreatePostFindByIdResultFromEntity(*post)

	return result, nil
}

func (s *PostService) FindAllByUserName(query queries.PostFindAllByUserNameQuery) (*queries.PostFindAllByUserNameResult, error) {
	posts, err := s.repo.FindAllByUserName(query.UserName)
	if err != nil {
		return nil, err
	}

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

	result := mapper.CreatePostFindAllByUserNameResult(posts)

	return result, nil
}

func (s *PostService) GetAll() (*queries.PostGetAllResult, error) {
	posts, err := s.repo.GetAll()
	if err != nil {
		return nil, err
	}

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

	result := mapper.CreatePostGetAllResult(posts)

	return result, nil
}

func (s *PostService) Update(cmd commands.UpdatePostCommand) (*common.PostResult, error) {
	post, err := s.repo.FindById(cmd.Id)
	if err != nil {
		return nil, err
	}

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

	post.Title = cmd.Title
	post.Description = cmd.Description
	post.Content = cmd.Content
	post.UpdatedAt = time.Now()

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

	result := mapper.CreatePostResultFromEntity(post)

	return result, nil
}

func (s *PostService) Delete(cmd commands.DeletePostCommand) error {
	post, err := s.repo.FindById(cmd.Id)
	if err != nil {
		return err
	}

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

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

	return nil
}
