package com.pressing.modules.sites;

import com.pressing.common.exception.ApiException;
import com.pressing.domain.site.Site;
import com.pressing.domain.site.SiteRepository;
import com.pressing.modules.sites.dto.SiteDtos.SiteRequest;
import com.pressing.modules.sites.dto.SiteDtos.SiteResponse;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.domain.Specification;
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 SiteService {

    private final SiteRepository siteRepository;

    public List<SiteResponse> sites(String q) {
        Specification<Site> spec = (root, query, cb) -> {
            if (q == null || q.isBlank()) {
                return cb.conjunction();
            }
            String search = "%" + q.trim().toLowerCase() + "%";
            List<Predicate> predicates = new ArrayList<>();

            predicates.add(cb.like(cb.lower(root.get("name")), search));
            predicates.add(cb.like(cb.lower(root.get("code")), search));
            predicates.add(cb.like(cb.lower(root.get("address")), search));
            predicates.add(cb.like(cb.lower(root.get("email")), search));

            return cb.or(predicates.toArray(new Predicate[0]));
        };

        return siteRepository.findAll(spec).stream()
                .map(this::toSite)
                .toList();
    }

    @Transactional
    public SiteResponse createSite(SiteRequest req) {
        if (req.code() != null && !req.code().isBlank() && siteRepository.existsByCode(req.code())) {
            throw ApiException.badRequest("Le code entreprise '" + req.code() + "' existe déjà.");
        }

        Site site = applySite(new Site(), req);
        Site saved = siteRepository.save(site);
        return toSite(saved);
    }

    @Transactional
    public SiteResponse updateSite(Long id, SiteRequest req) {
        Site site = siteRepository.findById(id)
                .orElseThrow(() -> ApiException.notFound("Site introuvable"));

        if (req.code() != null && !req.code().isBlank() && siteRepository.existsByCodeAndIdNot(req.code(), id)) {
            throw ApiException.badRequest("Le code entreprise '" + req.code() + "' est déjà utilisé.");
        }

        Site saved = siteRepository.save(applySite(site, req));
        return toSite(saved);
    }

    @Transactional
    public void deleteSite(Long id) {
        if (!siteRepository.existsById(id)) {
            throw ApiException.notFound("Site introuvable");
        }
        siteRepository.deleteById(id);
    }

    private Site applySite(Site site, SiteRequest req) {
        site.setName(req.name());
        site.setCode(req.code());
        site.setPhone(req.phone());
        site.setEmail(req.email());
        site.setAddress(req.address());
        site.setLogoUrl(req.logoUrl());
        site.setActivityDomain(req.activityDomain() == null || req.activityDomain().isBlank() ? "PRESSING" : req.activityDomain());
        site.setActive(req.active() == null || req.active());
        return site;
    }

    private SiteResponse toSite(Site s) {
        return new SiteResponse(
                s.getId(),
                s.getName(),
                s.getCode(),
                s.getPhone(),
                s.getEmail(),
                s.getAddress(),
                s.getLogoUrl(),
                s.getActivityDomain(),
                s.isActive()
        );
    }
}