package com.prudas.app.service;

import com.prudas.app.dto.ServiceOfferingRequest;
import com.prudas.app.dto.ServiceOfferingResponse;
import com.prudas.app.dto.ServiceProcessStepDto;
import com.prudas.app.entity.ServiceOffering;
import com.prudas.app.entity.ServiceProcessStep;
import com.prudas.app.exception.DuplicateResourceException;
import com.prudas.app.exception.ResourceNotFoundException;
import com.prudas.app.repository.ServiceOfferingRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

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

    private final ServiceOfferingRepository repository;

    public List<ServiceOfferingResponse> findPublishedForNav() {
        return repository.findByPublishedTrueAndShowInNavTrueOrderByDisplayOrderAsc().stream().map(this::toResponse).toList();
    }

    public List<ServiceOfferingResponse> findPublishedForHome() {
        return repository.findByPublishedTrueAndShowOnHomeTrueOrderByDisplayOrderAsc().stream().map(this::toResponse).toList();
    }

    public List<ServiceOfferingResponse> findAllPublished() {
        return repository.findByPublishedTrueOrderByDisplayOrderAsc().stream().map(this::toResponse).toList();
    }

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

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

    public List<ServiceOfferingResponse> findAllForAdmin() {
        return repository.findAll().stream().map(this::toResponse).toList();
    }

    @Transactional
    public ServiceOfferingResponse create(ServiceOfferingRequest request) {
        if (repository.existsBySlug(request.slug())) {
            throw new DuplicateResourceException("A service with slug '" + request.slug() + "' already exists");
        }
        ServiceOffering entity = ServiceOffering.builder()
                .slug(request.slug())
                .title(request.title())
                .tagline(request.tagline())
                .summary(request.summary())
                .content(request.content())
                .heroImageUrl(request.heroImageUrl())
                .contactEmail(request.contactEmail())
                .displayOrder(request.displayOrder())
                .published(request.published())
                .showInNav(request.showInNav())
                .showOnHome(request.showOnHome())
                .build();
        applySteps(entity, request.processSteps());
        return toResponse(repository.save(entity));
    }

    @Transactional
    public ServiceOfferingResponse update(Long id, ServiceOfferingRequest request) {
        ServiceOffering entity = repository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Service not found: " + id));

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

        entity.setSlug(request.slug());
        entity.setTitle(request.title());
        entity.setTagline(request.tagline());
        entity.setSummary(request.summary());
        entity.setContent(request.content());
        entity.setHeroImageUrl(request.heroImageUrl());
        entity.setContactEmail(request.contactEmail());
        entity.setDisplayOrder(request.displayOrder());
        entity.setPublished(request.published());
        entity.setShowInNav(request.showInNav());
        entity.setShowOnHome(request.showOnHome());

        entity.getProcessSteps().clear();
        applySteps(entity, request.processSteps());

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

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

    private void applySteps(ServiceOffering entity, List<ServiceProcessStepDto> steps) {
        if (steps == null) {
            return;
        }
        List<ServiceProcessStep> stepEntities = new ArrayList<>();
        for (ServiceProcessStepDto dto : steps) {
            stepEntities.add(ServiceProcessStep.builder()
                    .service(entity)
                    .stepOrder(dto.stepOrder())
                    .title(dto.title())
                    .description(dto.description())
                    .iconUrl(dto.iconUrl())
                    .build());
        }
        entity.getProcessSteps().addAll(stepEntities);
    }

    private ServiceOfferingResponse toResponse(ServiceOffering entity) {
        List<ServiceProcessStepDto> steps = entity.getProcessSteps().stream()
                .map(s -> new ServiceProcessStepDto(s.getId(), s.getStepOrder(), s.getTitle(), s.getDescription(), s.getIconUrl()))
                .toList();
        return new ServiceOfferingResponse(
                entity.getId(), entity.getSlug(), entity.getTitle(), entity.getTagline(),
                entity.getSummary(), entity.getContent(), entity.getHeroImageUrl(), entity.getContactEmail(),
                entity.getDisplayOrder(), entity.isPublished(), entity.isShowInNav(), entity.isShowOnHome(), steps
        );
    }
}
