package com.evseminar.service;

import com.evseminar.dto.SeminarDTO;
import com.evseminar.dto.VehicleDTO;
import com.evseminar.dto.VehicleRequest;
import com.evseminar.exception.BadRequestException;
import com.evseminar.exception.ResourceNotFoundException;
import com.evseminar.model.Vehicle;
import com.evseminar.model.VehicleColor;
import com.evseminar.model.VehicleFeature;
import com.evseminar.repository.RegistrationRepository;
import com.evseminar.repository.SeminarRepository;
import com.evseminar.repository.VehicleRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
public class VehicleService {

    private final VehicleRepository vehicleRepository;
    private final SeminarRepository seminarRepository;
    private final RegistrationRepository registrationRepository;

    public List<VehicleDTO> getAllVehicles() {
        return vehicleRepository.findAll().stream()
                .map(VehicleDTO::from)
                .toList();
    }

    public VehicleDTO getVehicleById(Long id) {
        Vehicle vehicle = vehicleRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Vehicle not found"));

        VehicleDTO dto = VehicleDTO.from(vehicle);

        List<SeminarDTO> upcomingSeminars = seminarRepository
                .findByVehicleVehicleIdAndSeminarDateAfterOrderBySeminarDateAsc(id, LocalDateTime.now())
                .stream()
                .map(s -> {
                    int booked = registrationRepository.countBookedSeats(s.getSeminarId());
                    return SeminarDTO.from(s, booked);
                })
                .toList();

        dto.setSeminars(upcomingSeminars);
        return dto;
    }

    @Transactional
    public VehicleDTO createVehicle(VehicleRequest request) {
        if (vehicleRepository.existsByModelNumber(request.getModelNumber())) {
            throw new BadRequestException("Model number already exists: " + request.getModelNumber());
        }
        Vehicle vehicle = Vehicle.builder()
                .modelNumber(request.getModelNumber())
                .name(request.getName())
                .nameZh(request.getNameZh())
                .description(request.getDescription())
                .descriptionZh(request.getDescriptionZh())
                .pictureUrl(request.getPictureUrl())
                .unitPrice(request.getUnitPrice())
                .vehicleType(request.getVehicleType())
                .rangeKm(request.getRangeKm())
                .batteryCapacityKwh(request.getBatteryCapacityKwh())
                .chargingTimeMin(request.getChargingTimeMin())
                .horsepower(request.getHorsepower())
                .topSpeedKmh(request.getTopSpeedKmh())
                .seatingCapacity(request.getSeatingCapacity())
                .warrantyYears(request.getWarrantyYears())
                .build();

        Vehicle saved = vehicleRepository.save(vehicle);
        applyFeaturesAndColors(saved, request);
        return VehicleDTO.from(vehicleRepository.save(saved));
    }

    @Transactional
    public VehicleDTO updateVehicle(Long id, VehicleRequest request) {
        Vehicle vehicle = vehicleRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Vehicle not found"));
        vehicle.setModelNumber(request.getModelNumber());
        vehicle.setName(request.getName());
        vehicle.setNameZh(request.getNameZh());
        vehicle.setDescription(request.getDescription());
        vehicle.setDescriptionZh(request.getDescriptionZh());
        vehicle.setPictureUrl(request.getPictureUrl());
        vehicle.setUnitPrice(request.getUnitPrice());
        vehicle.setVehicleType(request.getVehicleType());
        vehicle.setRangeKm(request.getRangeKm());
        vehicle.setBatteryCapacityKwh(request.getBatteryCapacityKwh());
        vehicle.setChargingTimeMin(request.getChargingTimeMin());
        vehicle.setHorsepower(request.getHorsepower());
        vehicle.setTopSpeedKmh(request.getTopSpeedKmh());
        vehicle.setSeatingCapacity(request.getSeatingCapacity());
        vehicle.setWarrantyYears(request.getWarrantyYears());

        vehicle.getVehicleFeatures().clear();
        vehicle.getVehicleColors().clear();
        applyFeaturesAndColors(vehicle, request);
        return VehicleDTO.from(vehicleRepository.save(vehicle));
    }

    @Transactional
    public void deleteVehicle(Long id) {
        Vehicle vehicle = vehicleRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Vehicle not found"));
        vehicle.setDeletedAt(LocalDateTime.now());
        vehicleRepository.save(vehicle);
    }

    private void applyFeaturesAndColors(Vehicle vehicle, VehicleRequest request) {
        if (request.getFeatures() != null) {
            for (int i = 0; i < request.getFeatures().size(); i++) {
                String name = request.getFeatures().get(i).trim();
                if (!name.isEmpty()) {
                    vehicle.getVehicleFeatures().add(VehicleFeature.builder()
                            .vehicle(vehicle)
                            .featureName(name)
                            .sortOrder(i)
                            .build());
                }
            }
        }
        if (request.getColors() != null) {
            request.getColors().stream()
                    .map(String::trim)
                    .filter(c -> !c.isEmpty())
                    .forEach(c -> vehicle.getVehicleColors().add(
                            VehicleColor.builder().vehicle(vehicle).colorName(c).build()));
        }
    }
}
