package mk.ukim.finki.it.reservengo.service.impl;

import mk.ukim.finki.it.reservengo.dto.localDTO.CreateLocalDetailsDTO;
import mk.ukim.finki.it.reservengo.model.domain.Local;
import mk.ukim.finki.it.reservengo.model.exceptions.LocalIdNotFoundException;
import mk.ukim.finki.it.reservengo.model.exceptions.LogoDeletionException;
import mk.ukim.finki.it.reservengo.model.exceptions.MenuDeletionException;
import mk.ukim.finki.it.reservengo.model.exceptions.PhotoDeletionException;
import mk.ukim.finki.it.reservengo.repository.LocalRepository;
import mk.ukim.finki.it.reservengo.service.intf.FileStorageService;
import mk.ukim.finki.it.reservengo.service.intf.LocalService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Service
public class LocalServiceImpl implements LocalService {

    private final LocalRepository localRepository;
    private final FileStorageService fileStorageService;

    public LocalServiceImpl(LocalRepository localRepository, FileStorageService fileStorageService) {
        this.localRepository = localRepository;
        this.fileStorageService = fileStorageService;
    }

    @Override
    public List<Local> listAll() {
        return localRepository.findAll();
    }

    @Override
    public Local findLocalById(Long id) {
        return localRepository.findById(id).orElseThrow(() -> new LocalIdNotFoundException(id));
    }

    @Override
    public void save(String name) {
        Local local = new Local(name);
        localRepository.save(local);
    }

    @Override
    public void delete(Long id) {
        Local local = localRepository.findById(id).orElseThrow(() -> new LocalIdNotFoundException(id));
        localRepository.delete(local);
    }

    @Override
    public void addLogo(Long localId, MultipartFile multipartFile) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));

        if (!multipartFile.isEmpty()) {
            String logoPath = fileStorageService.saveLogoFile(multipartFile);
            local.setLogoUrl(logoPath);
        }

        localRepository.save(local);
    }

    @Override
    public void deleteLogo(Long localId) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));
        String logoUrl = local.getLogoUrl();

        if (logoUrl != null && !logoUrl.isEmpty()) {
            Path filePath = Paths.get("uploads").resolve("logos").resolve(Paths.get(logoUrl).getFileName().toString());

            try {
                Files.deleteIfExists(filePath);
            } catch (IOException e) {
                throw new LogoDeletionException("Failed to delete logo from path: " + filePath, e);
            }
        }
        local.setLogoUrl(null);
        localRepository.save(local);
    }

    @Override
    public void uploadPhotos(Long localId, List<MultipartFile> photos) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));

        List<String> photoPaths = local.getLocalPhotos();

        if (photoPaths == null) {
            photoPaths = new ArrayList<>();
        }

        for (MultipartFile photo : photos) {
            if (!photo.isEmpty()) {
                String filePath = fileStorageService.saveLocalPhoto(localId, photo);
                photoPaths.add(filePath);
            }
        }
        local.setLocalPhotos(photoPaths);
        localRepository.save(local);
    }

    @Override
    public void deletePhotos(Long localId, List<String> photoPaths) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));

        List<String> uploadedPhotos = local.getLocalPhotos();

        if (uploadedPhotos == null) {
            uploadedPhotos = new ArrayList<>();
        }

        for (String photoPath : photoPaths) {
            if (uploadedPhotos.contains(photoPath)) {
                try {
                    fileStorageService.deletePhotoFile(photoPath);
                    uploadedPhotos.remove(photoPath);
                } catch (RuntimeException e) {
                    throw new PhotoDeletionException("Failed to delete photo: " + photoPath, e);
                }
            }
        }

        local.setLocalPhotos(uploadedPhotos);
        localRepository.save(local);
    }

    @Override
    public void uploadMenu(Long localId, MultipartFile localMenuFile) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));

        if (!localMenuFile.isEmpty()) {
            String menuPath = fileStorageService.saveLocalMenuPhoto(localId, localMenuFile);
            local.setMenuPhoto(menuPath);
        }

        localRepository.save(local);
    }

    @Override
    public void deleteMenu(Long localId) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));

        String menuPhotoPath = local.getMenuPhoto();

        if (menuPhotoPath != null && !menuPhotoPath.isEmpty()) {
            try {
                fileStorageService.deletePhotoFile(menuPhotoPath);
            } catch (RuntimeException e) {
                throw new MenuDeletionException("Failed to delete menu photo: " + menuPhotoPath, e);
            }
            local.setMenuPhoto(null);
            localRepository.save(local);
        }
    }

    @Override
    public void updateInfoLocal(Long localId, CreateLocalDetailsDTO createLocalDetailsDTO) {
        Local local = localRepository.findById(localId).orElseThrow(() -> new LocalIdNotFoundException(localId));

        local.setName(createLocalDetailsDTO.name());
        local.setDescription(createLocalDetailsDTO.description());
        local.setAddress(createLocalDetailsDTO.address());
        local.setWorkingHours(createLocalDetailsDTO.workingHours());
        local.setAvailableServices(createLocalDetailsDTO.services());
        local.setLocalPhotos(createLocalDetailsDTO.localPhotos());
        local.setMenuPhoto(createLocalDetailsDTO.menuPhoto());
        local.setMenuLink(createLocalDetailsDTO.menuLink());
        local.setContact(createLocalDetailsDTO.contact().toContact());
        local.setLogoUrl(createLocalDetailsDTO.logo());

        localRepository.save(local);
    }
}
