package com.prudas.app.service;

import com.prudas.app.dto.BlogPostRequest;
import com.prudas.app.dto.BlogPostResponse;
import com.prudas.app.dto.BlogPostSummaryResponse;
import com.prudas.app.dto.PageResponse;
import com.prudas.app.entity.BlogPost;
import com.prudas.app.exception.DuplicateResourceException;
import com.prudas.app.exception.ResourceNotFoundException;
import com.prudas.app.repository.BlogPostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class BlogService {

    private final BlogPostRepository repository;

    public PageResponse<BlogPostSummaryResponse> findPublished(Pageable pageable) {
        return PageResponse.from(repository.findByPublishedTrueOrderByPublishedAtDesc(pageable).map(this::toSummary));
    }

    public BlogPostResponse findPublishedBySlug(String slug) {
        return repository.findBySlugAndPublishedTrue(slug).map(this::toResponse)
                .orElseThrow(() -> new ResourceNotFoundException("Blog post not found: " + slug));
    }

    // --- admin -----------------------------------------------------------

    public PageResponse<BlogPostResponse> findAllForAdmin(Pageable pageable) {
        return PageResponse.from(repository.findAll(pageable).map(this::toResponse));
    }

    @Transactional
    public BlogPostResponse create(BlogPostRequest request) {
        if (repository.existsBySlug(request.slug())) {
            throw new DuplicateResourceException("A post with slug '" + request.slug() + "' already exists");
        }
        BlogPost entity = BlogPost.builder()
                .slug(request.slug())
                .title(request.title())
                .excerpt(request.excerpt())
                .content(request.content())
                .coverImageUrl(request.coverImageUrl())
                .authorName(request.authorName())
                .published(request.published())
                .publishedAt(request.published() ? Instant.now() : null)
                .build();
        return toResponse(repository.save(entity));
    }

    @Transactional
    public BlogPostResponse update(Long id, BlogPostRequest request) {
        BlogPost entity = repository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Blog post not found: " + id));

        if (!entity.getSlug().equals(request.slug()) && repository.existsBySlug(request.slug())) {
            throw new DuplicateResourceException("A post with slug '" + request.slug() + "' already exists");
        }

        boolean newlyPublished = request.published() && !entity.isPublished();

        entity.setSlug(request.slug());
        entity.setTitle(request.title());
        entity.setExcerpt(request.excerpt());
        entity.setContent(request.content());
        entity.setCoverImageUrl(request.coverImageUrl());
        entity.setAuthorName(request.authorName());
        entity.setPublished(request.published());
        if (newlyPublished) {
            entity.setPublishedAt(Instant.now());
        }

        return toResponse(repository.save(entity));
    }

    @Transactional
    public void delete(Long id) {
        if (!repository.existsById(id)) {
            throw new ResourceNotFoundException("Blog post not found: " + id);
        }
        repository.deleteById(id);
    }

    private BlogPostSummaryResponse toSummary(BlogPost e) {
        return new BlogPostSummaryResponse(e.getId(), e.getSlug(), e.getTitle(), e.getExcerpt(), e.getCoverImageUrl(), e.getAuthorName(), e.getPublishedAt());
    }

    private BlogPostResponse toResponse(BlogPost e) {
        return new BlogPostResponse(e.getId(), e.getSlug(), e.getTitle(), e.getExcerpt(), e.getContent(), e.getCoverImageUrl(), e.getAuthorName(), e.isPublished(), e.getPublishedAt());
    }
}
