package com.training.service;

import com.training.entities.Person;
import com.training.exceptions.ManagePeoplesException;
import com.training.repository.PersonJpaRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PersonService implements IPersonService {

    private final PersonJpaRepository personRepository;

    @Override
    @Transactional
    public Person createPerson(Person person) {
        try {
            log.info("Création d'une nouvelle personne: {} {}", person.getFirstName(), person.getLastName());

            if (person.getId() != null) {
                throw new ManagePeoplesException("L'ID doit être null lors de la création d'une personne");
            }

            Person savedPerson = personRepository.save(person);
            log.info("Personne créée avec succès avec l'ID: {}", savedPerson.getId());
            return savedPerson;

        } catch (Exception e) {
            log.error("Erreur lors de la création de la personne", e);
            throw new ManagePeoplesException("Erreur lors de la création de la personne: " + e.getMessage(), e);
        }
    }

    @Override
    public Optional<Person> getPersonById(Integer id) {
        try {
            log.info("Recherche de la personne avec l'ID: {}", id);
            return personRepository.findById(id);
        } catch (Exception e) {
            log.error("Erreur lors de la récupération de la personne avec l'ID: {}", id, e);
            throw new ManagePeoplesException("Erreur lors de la récupération de la personne: " + e.getMessage(), e);
        }
    }

    @Override
    public List<Person> getAllPersons() {
        try {
            log.info("Récupération de toutes les personnes");
            List<Person> persons = personRepository.findAll();
            log.info("Nombre de personnes trouvées: {}", persons.size());
            return persons;
        } catch (Exception e) {
            log.error("Erreur lors de la récupération de toutes les personnes", e);
            throw new ManagePeoplesException("Erreur lors de la récupération des personnes: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public Person updatePerson(Integer id, Person person) {
        try {
            log.info("Mise à jour de la personne avec l'ID: {}", id);

            Person existingPerson = personRepository.findById(id)
                    .orElseThrow(() -> new ManagePeoplesException("Personne non trouvée avec l'ID: " + id));

            // Mise à jour des champs
            existingPerson.setFirstName(person.getFirstName());
            existingPerson.setLastName(person.getLastName());
            existingPerson.setWeight(person.getWeight());
            existingPerson.setSize(person.getSize());
            existingPerson.setStreet(person.getStreet());
            existingPerson.setPostalCode(person.getPostalCode());
            existingPerson.setCity(person.getCity());
            existingPerson.setCountry(person.getCountry());

            Person updatedPerson = personRepository.save(existingPerson);
            log.info("Personne mise à jour avec succès: {}", updatedPerson.getId());
            return updatedPerson;

        } catch (ManagePeoplesException e) {
            throw e;
        } catch (Exception e) {
            log.error("Erreur lors de la mise à jour de la personne avec l'ID: {}", id, e);
            throw new ManagePeoplesException("Erreur lors de la mise à jour de la personne: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public void deletePerson(Integer id) {
        try {
            log.info("Suppression de la personne avec l'ID: {}", id);

            if (!personRepository.existsById(id)) {
                throw new ManagePeoplesException("Personne non trouvée avec l'ID: " + id);
            }

            personRepository.deleteById(id);
            log.info("Personne supprimée avec succès: {}", id);

        } catch (ManagePeoplesException e) {
            throw e;
        } catch (Exception e) {
            log.error("Erreur lors de la suppression de la personne avec l'ID: {}", id, e);
            throw new ManagePeoplesException("Erreur lors de la suppression de la personne: " + e.getMessage(), e);
        }
    }

    @Override
    public Optional<Person> findByFirstNameAndLastName(String firstName, String lastName) {
        try {
            log.info("Recherche de la personne: {} {}", firstName, lastName);
            return personRepository.findByFirstNameAndLastName(firstName, lastName);
        } catch (Exception e) {
            log.error("Erreur lors de la recherche de la personne: {} {}", firstName, lastName, e);
            throw new ManagePeoplesException("Erreur lors de la recherche de la personne: " + e.getMessage(), e);
        }
    }

    @Override
    public List<Person> findByCity(String city) {
        try {
            log.info("Recherche des personnes dans la ville: {}", city);
            return personRepository.findByCity(city);
        } catch (Exception e) {
            log.error("Erreur lors de la recherche des personnes dans la ville: {}", city, e);
            throw new ManagePeoplesException("Erreur lors de la recherche par ville: " + e.getMessage(), e);
        }
    }

    @Override
    public List<Person> findByCountry(String country) {
        try {
            log.info("Recherche des personnes dans le pays: {}", country);
            return personRepository.findByCountry(country);
        } catch (Exception e) {
            log.error("Erreur lors de la recherche des personnes dans le pays: {}", country, e);
            throw new ManagePeoplesException("Erreur lors de la recherche par pays: " + e.getMessage(), e);
        }
    }
}
