package com.codenetworkz.blog.services.impl;

import com.codenetworkz.blog.config.SlugGenerator;
import com.codenetworkz.blog.dtos.TagDto;
import com.codenetworkz.blog.exceptions.InternalServerException;
import com.codenetworkz.blog.exceptions.ResourceNotAvailable;

import com.codenetworkz.blog.mappers.TagMapper;
import com.codenetworkz.blog.models.Status;
import com.codenetworkz.blog.models.Tag;
import com.codenetworkz.blog.repositories.TagRepository;
import com.codenetworkz.blog.services.TagService;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Service
public class TagServiceImpl implements TagService {

    private final TagRepository tagRepository;
    private final TagMapper tagMapper;

    TagServiceImpl(TagRepository tagRepository,TagMapper tagMapper) {
        this.tagRepository = tagRepository;
        this.tagMapper = tagMapper;
    }

    @Override
    public Optional<TagDto> save(String tagName, String description) throws InternalServerException, ResourceNotAvailable {
        Optional<Tag> findObject;
        Optional<Tag> save ;
        Tag tag = new Tag();
        tag.setSlug(SlugGenerator.generateSlug(tagName));
        findObject = findByTagSlug(tag.getSlug());
        if(findObject.isPresent()){
            throw new InternalServerException(tagName+ " is already available");
        }
        tag.setName(tagName);
        tag.setDescription(description);
        tag.setCreatedBy("System");
        try {
            save = Optional.of(tagRepository.save(tag));
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");

        }

        return tagMapper.tagToTagDto(save);
    }

    @Override
    public Optional<TagDto> delete(String slug) throws InternalServerException, ResourceNotAvailable {
        Optional<Tag> findObject;
        Optional<Tag> save;
        findObject = findByTagSlug(slug);
        if(findObject.isEmpty()){
            throw new ResourceNotAvailable("Tag name is not available");
        }
        findObject.get().setIsDelete(Status.YES);
        findObject.get().setIsActive(Status.NO);
        findObject.get().setDeleteAt(LocalDateTime.now());
        try {
            save = Optional.of(tagRepository.save(findObject.get()));
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }
        return tagMapper.tagToTagDto(save);
    }

    @Override
    public Optional<TagDto> update(String slug, String tagName, String description) throws ResourceNotAvailable, InternalServerException {
        Optional<Tag> findObject;
        findObject = findByTagSlug(slug);
        if(findObject.isEmpty()){
            throw new ResourceNotAvailable("Tag name is not available");
        }
        findObject.get().setName(tagName);
        findObject.get().setDescription(description);
        findObject.get().setUpdateAt(LocalDateTime.now());
        findObject.get().setUpdateBy("System");
        try {
            Tag save = tagRepository.save(findObject.get());
          return  tagMapper.tagToTagDto(Optional.of(save));
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }
    }

    @Override
    public Optional<Tag> findByTagSlug(String slug) throws InternalServerException, ResourceNotAvailable {
        Optional<Tag> findObject ;
        try {
            findObject = tagRepository.findBySlugAndIsDelete(slug, Status.NO);
        } catch (Exception e) {
            throw new InternalServerException("There is a problem with Database Connection");
        }
        return findObject;
    }

    @Override
    public List<TagDto> findAll() throws InternalServerException {
        List<Tag> tags;
        try {
            tags = tagRepository.findAllAndIsDelete(Status.NO);
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }

        return tags.stream().map(tag -> tagMapper.tagToTagDto(Optional.of(tag)).get()).sorted((t1, t2) -> t1.getTagId().compareTo(t2.getTagId()) ).toList();
    }

    public Page<TagDto> getTagsWithPagination(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<Tag> tags;
        try {
            tags = tagRepository.findAllByIsDelete(Status.NO, pageable);
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }

        List<TagDto> tagDtos = tags.stream()
                .map(tag -> tagMapper.tagToTagDto(Optional.of(tag)).get())
                .toList();

        long totalElements = tags.getTotalElements();

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

    }

    @Override
    public Optional<TagDto> changeActivateStatus(String slug) throws InternalServerException, ResourceNotAvailable {
        Optional<Tag> findObject = findByTagSlug(slug);
        if(findObject.isEmpty()){
            throw new ResourceNotAvailable("Tag name is not available");
        }

       if (findObject.get().getIsActive().equals(Status.YES)) {
           findObject.get().setIsActive(Status.NO);
       } else {
           findObject.get().setIsActive(Status.YES);
       }

        try {
            Tag save = tagRepository.save(findObject.get());
            return tagMapper.tagToTagDto(Optional.of(save));
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }
    }

    @Override
    public Optional<TagDto> changeApprovalStatus(String slug) throws InternalServerException, ResourceNotAvailable {
        Optional<Tag> findObject = findByTagSlug(slug);
        if(findObject.isEmpty()){
            throw new ResourceNotAvailable("Tag name is not available");
        }

        if(findObject.get().getIsApproved()==null) {
            findObject.get().setIsApproved(Status.YES);
        }else if(findObject.get().getIsApproved().equals(Status.YES)){
            findObject.get().setIsApproved(Status.NO);
        }else {
            findObject.get().setIsApproved(Status.YES);
        }
        try {
            Tag save = tagRepository.save(findObject.get());
            return tagMapper.tagToTagDto(Optional.of(save));
        } catch (Exception e) {
            throw new InternalServerException("There is a problmes with Database Connection");
        }
    }


    @Override
    public List<TagDto> findByTagIds(List<Long> tagIds) throws InternalServerException, ResourceNotAvailable {
        if(tagIds.isEmpty()){
            throw new ResourceNotAvailable("Tag name is not available");
        }
        List<Tag> save;
        try {
           save =  tagRepository.findAllByIdInAndIsDelete(tagIds, Status.NO);
        } catch (Exception e) {
            throw new InternalServerException("There is a problem with Database Connection");
        }
        return  save.stream().map(tag -> tagMapper.tagToTagDto(Optional.of(tag)).get()).toList();
    }

    @Override
    public Page<TagDto> findAll(Integer pageNo, Integer pageSize) throws InternalServerException {

        List<Tag> all = tagRepository.findAll();
        Pageable pageRequest=PageRequest.of(pageNo - 1, pageSize);
        int startItem = pageNo * pageSize;
        List<Tag> list;

        if (all.size() < startItem) {
            list = Collections.emptyList();
        } else {
            int toIndex = Math.min(startItem + pageSize, all.size());
            list = all.subList(startItem, toIndex);
        }

        Page<Tag> bookPage
                = new PageImpl<Tag>(list, PageRequest.of(pageNo, pageSize), all.size());

      //  return bookPage;

        return  null;
    }

}
