package com.codenetworkz.blog.services.impl;

import com.codenetworkz.blog.config.SlugGenerator;
import com.codenetworkz.blog.dtos.CategoryDto;
import com.codenetworkz.blog.dtos.TagDto;
import com.codenetworkz.blog.exceptions.InternalServerException;
import com.codenetworkz.blog.exceptions.ResourceNotAvailable;
import com.codenetworkz.blog.mappers.CategoryMapper;
import com.codenetworkz.blog.models.Category;
import com.codenetworkz.blog.models.Status;
import com.codenetworkz.blog.models.Tag;
import com.codenetworkz.blog.repositories.CategoryRepository;
import com.codenetworkz.blog.services.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
public class CategoryServiceImpl implements CategoryService {

    private final CategoryRepository categoryRepository;
    private final CategoryMapper categoryMapper;

    public CategoryServiceImpl(CategoryRepository categoryRepository, CategoryMapper categoryMapper){
        this.categoryRepository=categoryRepository;
        this.categoryMapper=categoryMapper;
    }

    @Override
    public Optional<CategoryDto> save(String categoryName, String description) throws InternalServerException, ResourceNotAvailable {
        Category category = new Category();
        category.setSlug(SlugGenerator.generateSlug(categoryName));
        Optional<Category> findCategory = findByCategorySlug(category.getSlug());
        if(findCategory.isPresent()){
            throw new InternalServerException("Category already exists");
        }
        category.setName(categoryName);
        category.setDescription(description);
        category.setCreatedBy("System");
        Optional<Category> save;
        try {
            save = Optional.of(categoryRepository.save(category));
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database connection");
        }
        return categoryMapper.categoryToCategaryDto(save);
    }

    @Override
    public List<CategoryDto> findAll() throws InternalServerException {
        List<Category> categories;
        List<CategoryDto> categoryDtoList = new ArrayList<>();
        try {
            categories = categoryRepository.findAllAndIsDelete(Status.NO);
        } catch (Exception e) {
            throw new InternalServerException(e.getMessage());
        }

        if (!categories.isEmpty()){
            for (Category category : categories) {
                Optional<CategoryDto> categoryDto = categoryMapper.categoryToCategaryDto(Optional.of(category));
                categoryDto.ifPresent(categoryDtoList::add);
            }
            return categoryDtoList;
        }
       return categoryDtoList;
    }

    @Override
    public Optional<Category> findByCategorySlug(String categorySlug) throws InternalServerException {
        Optional<Category> findObject;
        try {
             findObject = categoryRepository.findBySlug(categorySlug);
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database connection");
        }
      return findObject;
    }

    @Override
   public Optional<CategoryDto> update(String categorySlug, String categoryName, String description) throws InternalServerException, ResourceNotAvailable{

        Optional<Category> category;
        Optional<Category> save;
        category = categoryRepository.findBySlug(categorySlug);
        if(category.isEmpty()){
            throw new InternalServerException("Category does not exist");
        }
        category.get().setName(categoryName);
        category.get().setDescription(description);
        category.get().setSlug(SlugGenerator.generateSlug(categoryName));
        category.get().setUpdateAt(LocalDateTime.now());
        category.get().setUpdateBy("System");
        try {
          save = Optional.of(categoryRepository.save(category.get()));
            categoryMapper.categoryToCategaryDto(save);
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database connection");
        }
        return categoryMapper.categoryToCategaryDto(save);

    }

    @Override
    public String delete(String categorySlug) throws InternalServerException, ResourceNotAvailable {
        Optional<Category> findCategory;
        findCategory = findByCategorySlug(categorySlug);
        if(findCategory.isEmpty()){
            throw new InternalServerException("Category does not exist");
        }
        findCategory.get().setIsDelete(Status.YES);
        findCategory.get().setDeleteAt(LocalDateTime.now());
        try {
            categoryRepository.save(findCategory.get());
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database connection");
        }
        return "Category Successfully Deleted.";
    }

    @Override
    public Optional<CategoryDto> changeActivateStatus(String categorySlug) throws InternalServerException {
        Optional<Category> findcategory = categoryRepository.findBySlug(categorySlug);

            if(findcategory.isEmpty()){
               throw new InternalServerException("Category does not exist");
            }
            if(findcategory.get().getIsActive().equals(Status.YES)){
                findcategory.get().setIsActive(Status.NO);
            }else {
                findcategory.get().setIsActive(Status.YES);
            }
            try {
                Optional<Category> save = Optional.of(categoryRepository.save(findcategory.get()));
                return categoryMapper.categoryToCategaryDto(save);
            } catch (Exception e) {
                throw new InternalServerException("There is problem with database connection");
            }
    }

    @Override
    public Optional<CategoryDto> changeApprovalStatus(String categorySlug) throws InternalServerException {
        Optional<Category> findcategory = categoryRepository.findBySlug(categorySlug);

        if(findcategory.isEmpty()){
            throw new InternalServerException("Category does not exist");
        }

        if (findcategory.get().getIsApproved()==null){
            findcategory.get().setIsApproved(Status.YES);
        } else {
            if(findcategory.get().getIsApproved().equals(Status.YES)){
                findcategory.get().setIsApproved(Status.NO);
            }else {
                findcategory.get().setIsApproved(Status.YES);
            }
        }

        try {
            Optional<Category> save = Optional.of(categoryRepository.save(findcategory.get()));
            return categoryMapper.categoryToCategaryDto(save);
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database connection");
        }
    }

    @Override
    public List<CategoryDto> findByCategoryIds(List<Long> categoryIds) throws InternalServerException {
        List<Category> findCategories;
        if(categoryIds.isEmpty()){
            throw new InternalServerException("Category does not exist");
        }
        try {
            findCategories =categoryRepository.findAllByIdInAndIsDelete(categoryIds, Status.NO);
        } catch (Exception e) {
            throw new InternalServerException("There is problem with database connection");
        }

       return categoryMapper.categoryToCategaryDtoList(findCategories);
    }

    @Override
    public Page<CategoryDto> getCategoryWithPagination(int page, int size) throws InternalServerException {
        // Create a Pageable instance with the desired page number and size
        Pageable pageable = PageRequest.of(page, size, Sort.by("id").ascending());

        // Fetch the paginated results
        Page<Category> categories;
        try {
            categories = categoryRepository.findAllByIsDelete(Status.NO, pageable);
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }
        List<CategoryDto> tagDtos = categories.stream()
                .map(category -> categoryMapper.categoryToCategaryDto(Optional.of(category)).get())
                .toList();

        long totalElements = categories.getTotalElements();

        return new PageImpl<>(tagDtos, pageable, totalElements);
    }
}
