package pl.polskalokalnie.listing;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import pl.polskalokalnie.moderation.TextModerationService;

@Service
public class ListingService {

    private static final int MAX_PHOTOS = 8;

    private final ListingRepository listingRepository;
    private final TextModerationService textModerationService;

    public ListingService(ListingRepository listingRepository, TextModerationService textModerationService) {
        this.listingRepository = listingRepository;
        this.textModerationService = textModerationService;
    }

    public List<ListingResponse> search(String city, OfferType offerType, PropertyType propertyType) {
        return listingRepository.findAll().stream()
                .filter(listing -> listing.getStatus() == ListingStatus.APPROVED)
                .filter(listing -> city == null || listing.getCity().equalsIgnoreCase(city.trim()))
                .filter(listing -> offerType == null || listing.getOfferType() == offerType)
                .filter(listing -> propertyType == null || listing.getPropertyType() == propertyType)
                .sorted(Comparator.comparing(PropertyListing::getCreatedAt).reversed())
                .map(ListingResponse::from)
                .toList();
    }

    @Transactional
    public ListingDetailResponse getById(Long id, boolean incrementView) {
        PropertyListing listing = listingRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Listing not found"));

        if (incrementView) {
            listing.setViewsCount((listing.getViewsCount() == null ? 0L : listing.getViewsCount()) + 1L);
            listing = listingRepository.save(listing);
        }

        return ListingDetailResponse.from(listing);
    }

    public List<ListingResponse> findMine(String ownerEmail) {
        return listingRepository.findAll().stream()
                .filter(listing -> ownerEmail != null && ownerEmail.equalsIgnoreCase(listing.getOwnerEmail()))
                .sorted(Comparator.comparing(PropertyListing::getCreatedAt).reversed())
                .map(ListingResponse::from)
                .toList();
    }

    @Transactional
    public ListingDetailResponse create(ListingCreateRequest request, String ownerEmail) {
        textModerationService.validateOrThrow(
                request.title(), request.description(), request.city(), request.address(),
                request.district(), request.street(), request.contactName());

        PropertyListing listing = new PropertyListing();
        listing.setTitle(request.title().trim());
        listing.setDescription(request.description().trim());
        listing.setOfferType(request.offerType());
        listing.setPropertyType(request.propertyType());
        listing.setCity(request.city().trim());
        listing.setAddress(trimToNull(request.address()));
        listing.setPrice(request.price());
        listing.setArea(request.area());
        listing.setRooms(request.rooms());

        listing.setMarket(trimToNull(request.market()));
        listing.setDistrict(trimToNull(request.district()));
        listing.setStreet(trimToNull(request.street()));
        listing.setBuilding(trimToNull(request.building()));
        listing.setFloor(trimToNull(request.floor()));
        listing.setBuildingFloors(trimToNull(request.buildingFloors()));
        listing.setYearBuilt(request.yearBuilt());
        listing.setCondition(trimToNull(request.condition()));
        listing.setOwnership(trimToNull(request.ownership()));
        listing.setContactName(trimToNull(request.contactName()));
        listing.setContactPhone(trimToNull(request.contactPhone()));
        listing.setContactEmail(trimToNull(request.contactEmail()));
        listing.setRentExtra(request.rentExtra());
        listing.setAvailableFrom(trimToNull(request.availableFrom()));
        listing.setFurnishing(trimToNull(request.furnishing()));
        listing.setBuildingType(trimToNull(request.buildingType()));
        listing.setBuildingMaterial(trimToNull(request.buildingMaterial()));
        listing.setWindows(trimToNull(request.windows()));
        listing.setExposure(trimToNull(request.exposure()));
        listing.setRoomHeight(trimToNull(request.roomHeight()));
        listing.setLat(request.lat());
        listing.setLng(request.lng());

        listing.setMedia(cleanList(request.media()));
        listing.setAmenities(cleanList(request.amenities()));

        List<String> photos = limitPhotos(request.photos());
        listing.setPhotos(photos);
        listing.setCoverPhoto(photos.isEmpty() ? null : photos.get(0));
        listing.setVirtualTourUrl(normalizeVirtualTourUrl(request.virtualTourUrl()));

        listing.setOwnerEmail(ownerEmail);
        listing.setStatus(ListingStatus.PENDING);

        return ListingDetailResponse.from(listingRepository.save(listing));
    }

    // --- Moderacja (admin) ---

    public List<ListingResponse> findAllForModeration() {
        return listingRepository.findAll().stream()
                .sorted(Comparator.comparing(PropertyListing::getCreatedAt).reversed())
                .map(ListingResponse::from)
                .toList();
    }

    public ListingResponse changeStatus(Long id, ListingStatus status) {
        PropertyListing listing = listingRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Listing not found"));
        listing.setStatus(status);
        return ListingResponse.from(listingRepository.save(listing));
    }

    public void delete(Long id) {
        if (!listingRepository.existsById(id)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Listing not found");
        }
        listingRepository.deleteById(id);
    }

    private static String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private static List<String> cleanList(List<String> values) {
        List<String> cleaned = new ArrayList<>();
        if (values != null) {
            for (String value : values) {
                String trimmed = trimToNull(value);
                if (trimmed != null && !cleaned.contains(trimmed)) {
                    cleaned.add(trimmed);
                }
            }
        }
        return cleaned;
    }

    private static List<String> limitPhotos(List<String> photos) {
        List<String> result = new ArrayList<>();
        if (photos != null) {
            for (String photo : photos) {
                if (photo != null && !photo.isBlank()) {
                    result.add(photo);
                    if (result.size() >= MAX_PHOTOS) {
                        break;
                    }
                }
            }
        }
        return result;
    }

    private static String normalizeVirtualTourUrl(String value) {
        String normalized = trimToNull(value);
        if (normalized == null) {
            return null;
        }
        if (normalized.length() > 1200) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Link do wirtualnego spaceru jest zbyt długi");
        }

        try {
            URI uri = new URI(normalized);
            String scheme = uri.getScheme();
            String host = uri.getHost();
            if (scheme == null || host == null) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Podaj poprawny link URL do wirtualnego spaceru");
            }
            if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Link do wirtualnego spaceru musi zaczynać się od http:// lub https://");
            }
            return uri.toString();
        } catch (URISyntaxException ex) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Podaj poprawny link URL do wirtualnego spaceru");
        }
    }
}
