package egovframework.com.mtdata.config.dbConn.mySql;

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import egovframework.com.mtdata.database.vo.DatabaseInfoVO;

public class CreateYaml {
	private static final Logger log = LoggerFactory.getLogger(CreateYaml.class);
	private static final Map<String, Object> fixedConfigurations;
	static {
		Map<String, Object> config = new HashMap<>();
		config.put("lock_timeout", "120s");
		config.put("replica_batch_size", 10000);
		config.put("replay_max_rows", 10000);
		config.put("batch_retention", "1 day");
		config.put("copy_max_memory", "300M");
		config.put("copy_mode", "file");
		config.put("out_dir", "/tmp");
		config.put("sleep_loop", 1);
		config.put("on_error_replay", "continue");
		config.put("type", "mysql");
		config.put("limit_tables", null);
//		config.put("limit_tables", Collections.emptyList());
		config.put("skip_tables", null);
//		config.put("skip_tables", Collections.emptyList());

		fixedConfigurations = Collections.unmodifiableMap(config);
	}

	public static void addFixedConfigurations(Map<String, Object> source) {
		source.putAll(fixedConfigurations);
	}

	public void createYaml(List<DatabaseInfoVO> databaseInfoList) throws IOException {
		log.info("Current user: {}", System.getProperty("user.name"));

		Path filePath = determineFilePath();
		backupExistingFile(filePath);

		InputStream input = getClass().getClassLoader().getResourceAsStream("config/chameleon-setting.yaml");

		if (input == null) {
			log.error("Resource config/chameleon-setting.yaml not found.");
			return;
		}

		Yaml yaml = new Yaml();
		Map<String, Object> data = yaml.load(input);

		updateSourceSection(data, databaseInfoList);

		DumperOptions op = new DumperOptions();
		op.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
		op.setPrettyFlow(true);
		yaml = new Yaml(op);

		try (FileWriter writer = new FileWriter(filePath.toString())) {
			yaml.dump(data, writer);
		} catch (IOException e) {
			log.error("Failed to create new YAML file", e);
		}
	}

	private Path determineFilePath() {
		String osName = System.getProperty("os.name").toLowerCase();
		String saveDir = osName.contains("win") ? System.getProperty("user.home") + "\\Desktop"
				: "/home/dpc/.pg_chameleon/configuration";
		log.info("Saving file to: {}", saveDir);
		return Paths.get(saveDir, "default.yml");
	}

	private void backupExistingFile(Path filePath) {
		if (Files.exists(filePath)) {
			String backupFileName = "default_"
					+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".yml";
			Path backupPath = Paths.get(filePath.getParent().toString(), backupFileName);
			try {
				Files.move(filePath, backupPath);
				log.info("Backup created: {}", backupPath);
			} catch (IOException e) {
				log.error("Failed to backup existing file", e);
			}
		}
	}

	private void updateSourceSection(Map<String, Object> data, List<DatabaseInfoVO> databaseInfoList) {
		Map<String, Object> sources = (Map<String, Object>) data.computeIfAbsent("sources", k -> new LinkedHashMap<>());
		for (DatabaseInfoVO vo : databaseInfoList) {
			Map<String, Object> source = new LinkedHashMap<>();
			source.put("db_conn", Map.of("host", vo.getDbConnIp(), "port", vo.getDbConnPort(), "user",
					vo.getDbConnUser(), "password", vo.getDbConnPw(), "charset", "utf8", "connect_timeout", 10));

			Map<String, String> schemaMappings = new LinkedHashMap<>();
			if (vo.getDbNmList().contains(", ")) {
				for (String dbName : vo.getDbNmList().split(", ")) {
					schemaMappings.put(dbName, dbName);
				}
			} else {
				schemaMappings.put(vo.getDbNmList(), vo.getDbNmList());
			}

			List<String> grantSelectTo = new ArrayList<>();
			grantSelectTo.add("migration_user");
			source.put("schema_mappings", schemaMappings);
			source.put("my_server_id", vo.getDbConnId());
			source.put("grant_select_to", grantSelectTo);
			addFixedConfigurations(source);

			sources.put(vo.getPgSourceNm(), source);
		}
	}
}
