package com.example.demo.service.impl;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
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.nio.file.attribute.PosixFilePermission;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.imageio.ImageIO;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.example.demo.config.FileUploadConfig;
import com.example.demo.entity.BannerSize;
import com.example.demo.entity.FileUploadModel;
import com.example.demo.exception.FileSpaceException;
import com.example.demo.repository.BannerSizeRepo;
import com.example.demo.service.FileUploadItf;

import net.lingala.zip4j.ZipFile;

@Service
public class FileUploadService implements FileUploadItf {

	@Autowired
	private BannerSizeRepo repo;

	private final Path dirLocation;

	@Value("${image.content.type}")
	private String imageContentType;

	@Value("${video.content.type}")
	private String videoContentType;

	FileUploadConfig congig = new FileUploadConfig();

	@Autowired
	private FileUploadService(FileUploadConfig fileUploadConfig) {
		this.dirLocation = Paths.get(fileUploadConfig.getLocation()).toAbsolutePath().normalize();

	}

	public void initlization() {

		try {
			Files.createDirectories(this.dirLocation);
		} catch (Exception ex) {
			throw new FileSpaceException("Unable to Create The Directory!");
		}

	}

	public FileUploadModel saveFile(MultipartFile file, String AdType, UUID sizeof, String cusheight, String cuswidth,
			String custome) throws IOException {
		String fileCode = RandomStringUtils.randomAlphanumeric(18);
		FileUploadModel Response = new FileUploadModel();
		String fill = file.getContentType();
		String[] valu = fill.split("/");
		String cal = null;
		for (String sb : valu) {
			cal = sb;
		}

		if (AdType.equals("B_IMG")) {
			if (supportedImageContent(file.getContentType())) {
				BufferedImage img = null;
				try {
					img = ImageIO.read(file.getInputStream());
				} catch (IOException e) {
					e.printStackTrace();
				}

				// size validation code
				boolean sizecheck = file.getSize() >= 5000;
				if (!sizecheck) {
					Response.setFilePath(fileCode + "." + cal);
					Response.setMessage("Invalid Image Size!");
					return Response;
				}

				Integer width = img.getWidth();
				Integer height = img.getHeight();

				String size = img.getWidth() + "X" + img.getHeight();
				if (!supportedHeightWidth(size, sizeof, cusheight, cuswidth, custome)) {

					Response.setFilePath(fileCode + "." + cal);
					Response.setMessage("Invalid Image Height and Width!");
					return Response;
				}
				String fileName = file.getOriginalFilename();
				System.out.println("filename :" + fileName);
				String video = file.getContentType();
				String type = fileName.substring(fileName.indexOf(".") + 1);
				Path dfile = this.dirLocation.resolve(fileCode + "." + cal);
				Files.copy(file.getInputStream(), dfile, StandardCopyOption.REPLACE_EXISTING);
				Set<PosixFilePermission> perms = new HashSet<>();
				perms.add(PosixFilePermission.OWNER_READ);
				perms.add(PosixFilePermission.OWNER_WRITE);
				perms.add(PosixFilePermission.OWNER_EXECUTE);
				perms.add(PosixFilePermission.GROUP_EXECUTE);
				perms.add(PosixFilePermission.GROUP_READ);
				perms.add(PosixFilePermission.GROUP_WRITE);
				perms.add(PosixFilePermission.OTHERS_EXECUTE);
				perms.add(PosixFilePermission.OTHERS_READ);
				perms.add(PosixFilePermission.OTHERS_WRITE);
				Files.setPosixFilePermissions(dfile, perms);
				Response.setFilePath(fileCode + "." + cal);
				Response.setMessage("File Uploaded Successfully!");
				return Response;
			} else {
				Response.setFilePath(fileCode + "." + cal);
				Response.setMessage("Invalid Content Type!");
				return Response;
			}
		} else if (AdType.equals("V_LINEAR")) {
			if (!supportedVideoContent(file.getContentType())) {

				Response.setFilePath(fileCode + "." + cal);
				Response.setMessage("Invalid Content Type!");
				return Response;
			} else {
				String fileName = file.getOriginalFilename();
				String video = file.getContentType();
				String type = fileName.substring(fileName.indexOf(".") + 1);

				// size validation code
				boolean sizecheck = file.getSize() >= 300000;
				if (!sizecheck) {
					Response.setFilePath(fileCode + "." + cal);
					Response.setMessage("Invalid Image Size!");
					return Response;
				}

				Path dfile = this.dirLocation.resolve(fileCode + "." + cal);
				Files.copy(file.getInputStream(), dfile, StandardCopyOption.REPLACE_EXISTING);
				Set<PosixFilePermission> perms = new HashSet<>();
				perms.add(PosixFilePermission.OWNER_READ);
				perms.add(PosixFilePermission.OWNER_WRITE);
				perms.add(PosixFilePermission.OWNER_EXECUTE);
				perms.add(PosixFilePermission.GROUP_EXECUTE);
				perms.add(PosixFilePermission.GROUP_READ);
				perms.add(PosixFilePermission.GROUP_WRITE);
				perms.add(PosixFilePermission.OTHERS_EXECUTE);
				perms.add(PosixFilePermission.OTHERS_READ);
				perms.add(PosixFilePermission.OTHERS_WRITE);
				Files.setPosixFilePermissions(dfile, perms);
				Response.setFilePath(fileCode + "." + cal);
				Response.setMessage("File Uploaded Successfully!");
				return Response;
			}

		} else if (AdType.equals("B_HTML")) {
			if (!supportedHTMLContent(file.getContentType())) {

				Response.setFilePath(fileCode + "." + cal);
				Response.setMessage("Invalid Content Type!");
				return Response;
			} else {
				Path dfile = this.dirLocation.resolve(file.getOriginalFilename());
				Path deletefile = Paths.get(file.getOriginalFilename());
				Path source = Paths.get(dfile.toString());
				Path traget = Paths.get(dirLocation.toString());
				Files.copy(file.getInputStream(), dfile, StandardCopyOption.REPLACE_EXISTING);
				File filepathh = unzipFolderZip4j(source, traget);
				ZipInputStream zis = new ZipInputStream(new FileInputStream(filepathh.getAbsoluteFile()));
				ZipEntry entry = zis.getNextEntry();

				char[] chararr = entry.toString().toCharArray();
				char pattern = '/';
				int count = 0;
				for (int j = 0; j < entry.toString().length(); j++) {
					if (pattern == chararr[j]) {
						count = j;
						break;

					}
				}

				String mainfolder = entry.toString().substring(0, count) + File.separator;

				Response.setFileExistPathCheck(
						Paths.get(traget + File.separator + file.getOriginalFilename().toString()));

				if (mainfolder.contains(" ")) {
					File stream = new File(traget + File.separator + mainfolder);
					mainfolder = mainfolder.toString().replace(" ", "_");
					FileUtils.deleteDirectory(new File(traget + File.separator + mainfolder));
					File replacename = new File(traget + File.separator + mainfolder);
					if (stream.renameTo(replacename)) {
						FileUtils.deleteDirectory(new File(stream.getAbsolutePath()));

					} else {

					}
				}

				FilePermission(true, "777", traget + File.separator + mainfolder);

				File FileReader = new File(traget + File.separator + mainfolder);

				File[] listOfFiles = FileReader.listFiles();

				String downloadpath;

				HashMap<String, String> filepath = new HashMap<String, String>();
				HashMap<String, String> htmlfile = new HashMap<String, String>();

				filepath = IndexFileValidation(listOfFiles);

				for (Map.Entry m : filepath.entrySet()) {

					if (m.getValue().toString().contains("index.html")) {
						Response.setFilePath(m.getValue().toString().substring(dirLocation.toString().length() + 1,
								m.getValue().toString().length()));
						Response.setMessage("File Uploaded Successfully!");
						return Response;

					} else {
						htmlfile.put(m.getKey().toString(), m.getValue().toString());
					}
				}

				System.out.println(" Filtered  html :" + htmlfile.size());

				if (htmlfile.size() == 1) {
					for (Map.Entry m : htmlfile.entrySet()) {
						Response.setFilePath(m.getValue().toString().substring(dirLocation.toString().length() + 1,
								m.getValue().toString().length()));
						Response.setMessage("File Uploaded Successfully!");
						return Response;
					}
				} else {
					Response.setFilePath("INDEX.HTML FILE MISSING");
					Response.setMessage("File Not Uploaded!");
					FileUtils.deleteDirectory(new File(traget + File.separator + mainfolder));
					return Response;
				}

				zis.close();
			}
		}
		Response.setFilePath(fileCode + "." + cal);
		Response.setMessage("Invalid Adtype!");
		return Response;

	}

	public static File unzipFolderZip4j(Path source, Path target) throws IOException {

		ZipFile file = new ZipFile(((Path) source).toFile());
		file.extractAll(target.toString());

		File filepathhh = file.getFile();
		return filepathhh;
	}

	private static void FilePermission(boolean recursive, String permission, String directoryFile) throws IOException {
		String osName = System.getProperty("os.name");
		String command = "chmod";
		if (recursive) {
			command += " -R";
		}

		Runtime.getRuntime().exec(command + " " + permission + " " + directoryFile);

	}

	private HashMap<String, String> IndexFileValidation(File[] listOfFiles) {

		HashMap<String, String> filepath = new HashMap<String, String>();

		for (int j = 0; j < listOfFiles.length; j++) {
			if (listOfFiles[j].isFile() && listOfFiles[j].getName().startsWith("._") != true) {
				if (listOfFiles[j].getName().endsWith(".html")) {
					filepath.put(listOfFiles[j].getName(), listOfFiles[j].toString());
				}
			} else if (listOfFiles[j].isDirectory() && listOfFiles[j].getName().startsWith("__") != true) {
				File folderdir = new File(listOfFiles[j].toString());
				File[] listOfFiless = folderdir.listFiles();
				HashMap<String, String> dirfilepath = new HashMap<String, String>();
				dirfilepath = IndexFileValidation(listOfFiless);

				for (Map.Entry m : dirfilepath.entrySet()) {

					filepath.put(m.getKey().toString(), m.getValue().toString());
				}

			}

		}
		return filepath;
	}

	private boolean supportedHeightWidth(String size, UUID sizeof, String cusheight, String cuswidth, String custome) {

		System.out.println("asdasdasd :" + custome);

		if (custome.equals("no")) {
			BannerSize bannerdetail = repo.findById(sizeof).orElse(null);
			String bannersize = null;
			bannersize = bannerdetail.getHeight() + "X" + bannerdetail.getWidth();

			if (size.equalsIgnoreCase(bannersize)) {
				return true;
			}

		} else {
			String cussize = null;
			cussize = cusheight + "X" + cuswidth;
			if (size.equals(cussize)) {
				return true;
			}
		}

		return false;
	}

	private boolean supportedVideoContent(String videoType) {

		List<String> VideocontentType = Arrays.asList(videoContentType.split(","));

		for (String videocontent : VideocontentType) {
			if (videoType.equals(videocontent)) {
				return true;
			}
		}
		return false;
	}

	private boolean supportedImageContent(String contentType) {

		List<String> myContentType2 = Arrays.asList(imageContentType.split(","));

		for (String content : myContentType2) {
			if (contentType.equals(content)) {
				return true;
			}
		}
		return false;
	}

	private boolean supportedHTMLContent(String htmltype) {
		if (htmltype.equals("application/zip") || htmltype.equals("application/x-zip-compressed")
				|| htmltype.equals("application/octet-stream") || htmltype.equals("application/x-compress")
				|| htmltype.equals("application/x-compressed") || htmltype.equals("multipart/x-zip")
				|| htmltype.equals("application/x-iso9660-image") || htmltype.equals("application/x-7z-compressed")
				|| htmltype.equals("application/x-rar-compressed") || htmltype.equals("application/gzip")
				|| htmltype.equals("application/x-tar") || htmltype.equals("application/vnd.rar")) {
			return true;
		}
		return false;

	}
}
