package com.petshop.backend.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
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.nio.file.StandardCopyOption;
import java.util.Locale;
import java.util.UUID;

@Service
public class CatalogImageStorageService {

    private static final String PET_PREFIX = "/uploads/pets/";
    private static final String PRODUCT_PREFIX = "/uploads/products/";
    private static final String BLOB_PETS = "pets";
    private static final String BLOB_PRODUCTS = "products";

    @Value("${app.upload.base-dir:uploads}")
    private String uploadBaseDir;

    @Autowired
    private AzureBlobService blobService;

    public String storePetImage(MultipartFile file) throws IOException {
        String extension = resolveExtension(file.getOriginalFilename());
        String filename = UUID.randomUUID() + extension;
        if (blobService.isEnabled()) {
            blobService.upload(BLOB_PETS, filename, file.getBytes());
        } else {
            Path directory = Paths.get(uploadBaseDir, "pets").toAbsolutePath().normalize();
            Files.createDirectories(directory);
            Files.copy(file.getInputStream(), directory.resolve(filename).normalize(), StandardCopyOption.REPLACE_EXISTING);
        }
        return PET_PREFIX + filename;
    }

    public String storeProductImage(MultipartFile file) throws IOException {
        String extension = resolveExtension(file.getOriginalFilename());
        String filename = UUID.randomUUID() + extension;
        if (blobService.isEnabled()) {
            blobService.upload(BLOB_PRODUCTS, filename, file.getBytes());
        } else {
            Path directory = Paths.get(uploadBaseDir, "products").toAbsolutePath().normalize();
            Files.createDirectories(directory);
            Files.copy(file.getInputStream(), directory.resolve(filename).normalize(), StandardCopyOption.REPLACE_EXISTING);
        }
        return PRODUCT_PREFIX + filename;
    }

    public Resource loadPetImage(String storedPath) {
        String filename = extractFilename(storedPath, PET_PREFIX);
        if (blobService.isEnabled()) {
            return new ByteArrayResource(blobService.download(BLOB_PETS, filename));
        }
        Resource resource = new PathResource(resolveStoredPath(storedPath, Paths.get(uploadBaseDir, "pets").toAbsolutePath().normalize(), PET_PREFIX));
        if (!resource.exists()) throw new IllegalArgumentException("Image file was not found");
        return resource;
    }

    public Resource loadProductImage(String storedPath) {
        String filename = extractFilename(storedPath, PRODUCT_PREFIX);
        if (blobService.isEnabled()) {
            return new ByteArrayResource(blobService.download(BLOB_PRODUCTS, filename));
        }
        Resource resource = new PathResource(resolveStoredPath(storedPath, Paths.get(uploadBaseDir, "products").toAbsolutePath().normalize(), PRODUCT_PREFIX));
        if (!resource.exists()) throw new IllegalArgumentException("Image file was not found");
        return resource;
    }

    public MediaType resolveMediaType(Resource resource) {
        return MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM);
    }

    public MediaType resolveMediaTypeByName(String filename) {
        return MediaTypeFactory.getMediaType(filename).orElse(MediaType.APPLICATION_OCTET_STREAM);
    }

    public void deletePetImage(String storedPath) throws IOException {
        if (storedPath == null || storedPath.isBlank()) return;
        String filename = extractFilename(storedPath, PET_PREFIX);
        if (blobService.isEnabled()) {
            blobService.delete(BLOB_PETS, filename);
        } else {
            Files.deleteIfExists(resolveStoredPath(storedPath, Paths.get(uploadBaseDir, "pets").toAbsolutePath().normalize(), PET_PREFIX));
        }
    }

    public void deleteProductImage(String storedPath) throws IOException {
        if (storedPath == null || storedPath.isBlank()) return;
        String filename = extractFilename(storedPath, PRODUCT_PREFIX);
        if (blobService.isEnabled()) {
            blobService.delete(BLOB_PRODUCTS, filename);
        } else {
            Files.deleteIfExists(resolveStoredPath(storedPath, Paths.get(uploadBaseDir, "products").toAbsolutePath().normalize(), PRODUCT_PREFIX));
        }
    }

    private String extractFilename(String storedPath, String prefix) {
        if (storedPath == null || !storedPath.startsWith(prefix)) throw new IllegalArgumentException("Image file was not found");
        String filename = storedPath.substring(prefix.length());
        if (filename.isBlank() || filename.contains("/") || filename.contains("\\") || filename.contains("..")) throw new IllegalArgumentException("Image file was not found");
        return filename;
    }

    private Path resolveStoredPath(String storedPath, Path directory, String prefix) {
        if (storedPath == null || storedPath.isBlank() || !storedPath.startsWith(prefix)) {
            throw new IllegalArgumentException("Image file was not found");
        }
        String filename = storedPath.substring(prefix.length());
        if (filename.isBlank() || filename.contains("/") || filename.contains("\\") || filename.contains("..")) {
            throw new IllegalArgumentException("Image file was not found");
        }
        Path resolved = directory.resolve(filename).normalize();
        if (!resolved.startsWith(directory)) {
            throw new IllegalArgumentException("Image file was not found");
        }
        return resolved;
    }

    private String resolveExtension(String originalFilename) {
        if (originalFilename == null) {
            return ".jpg";
        }
        int extensionIndex = originalFilename.lastIndexOf('.');
        if (extensionIndex < 0 || extensionIndex == originalFilename.length() - 1) {
            return ".jpg";
        }
        String extension = originalFilename.substring(extensionIndex).toLowerCase(Locale.ROOT);
        return switch (extension) {
            case ".jpg", ".jpeg", ".png", ".gif", ".webp" -> extension;
            default -> ".jpg";
        };
    }
}
