# coding=utf8
# encoding=utf8
"""
Manages data in CSV format files
"""

__author__ = "Roland Trouville"
__copyright__ = "Copyright 2015+, Consortium MonPaGe"
__license__ = "Creative Commons 4.0 By-Nc-Sa"
__maintainer__ = "Roland Trouville"
__email__ = "contact.monpage@gmail.com"
__status__ = "Production"


import codecs
import logging
import sys
import unicodedata
import chardet
from tools.ui_tools import UITools

logger = logging.getLogger(__name__)


class CSVManager(object):
	"""
	Static Class to manage CSV files
	"""

	@staticmethod
	def get_file_encoding(filename: str) -> str:
		"""
		Detect the character encoding of a text file.

		Uses the `chardet` library if available; otherwise defaults to "utf-8".

		Args:
			filename (str): Path to the file to analyze.

		Returns:
			str: Detected encoding of the file, or "utf-8" if chardet is not installed.
		"""
		if "chardet" not in sys.modules:
			return "utf-8"
		f = open(filename, "rb")
		tmp = chardet.detect(f.read())
		f.close()
		return tmp["encoding"]

	@staticmethod
	def read_file(filename, separator="\t", order_index=-1):
		"""
		Read a CSV file data
		:param filename: the path+filename of the CSV file to read
		:param separator: the separator used in the CSV file
		:param order_index: which column will be used to sort the data. if -1, we use natural sort order
		:return: array of array containing for each line, and array of the columns
		"""
		logger.info(f"Reading CSV file {filename}")
		encoding = CSVManager.get_file_encoding(filename)
		logger.info(f"Detected encoding: {encoding}")
		f = open(filename, "r", encoding=encoding, newline=None)
		ret_tmp = {}
		ret = []
		try:
			line = f.readline()
		except UnicodeDecodeError as e:
			UITools.error_log(
				e, "CSV readfile " + filename + " (detected: " + encoding + ")"
			)
			logger.error(f"UnicodeDecodeError: {e}")
			return ret
		counter = 0
		while line:
			values = line.rstrip().split(separator)
			for i in range(0, len(values)):
				values[i] = values[i].strip()
			if order_index > -1:
				try:
					ret_tmp.update({int(values[order_index]): values})
				except ValueError:
					ret_tmp.update({values[order_index]: values})
			else:
				ret_tmp.update({counter: values})
			line = f.readline()
			counter += 1

		for key, value in sorted(ret_tmp.items()):
			ret.append(value)
		return ret

	@staticmethod
	def add_lines(filename, separator, data):
		"""
		Adds lines to a pre-existing CSV file
		:param filename: the path+filename of the CSV file to read
		:param separator: the separator used in the CSV file
		:param data: array of array of the column data to add
		:return: None
		"""
		CSVManager.write_file(filename, separator, data, "a+")

	@staticmethod
	def overwrite_lines(filename, separator, data):
		"""
		Overwrite a csv file with data
		:param filename: the path+filename of the CSV file to read
		:param separator: the separator used in the CSV file
		:param data: array of array of the column data to add
		:return: None
		"""
		CSVManager.write_file(filename, separator, data, "w")

	@staticmethod
	def remove_line(filename, separator, column_index, value):
		"""
		Remove one line in a CSV file
		:param filename: the path+filename of the CSV file to read
		:param separator: the separator used in the CSV file
		:param column_index: the id of the column we have to match to delete
		:param value: the value of the column we are look for to delete the line
		:return: None
		"""
		values = CSVManager.read_file(filename, separator, -1)
		to_drop = -1
		for i in range(0, len(values)):
			if values[i][column_index] == value:
				to_drop = i

		if to_drop != -1:
			values.pop(to_drop)

		CSVManager.write_file(filename, separator, values, "w+")

	@staticmethod
	def reset_file(filename):
		"""
		Clear the contents of a file by opening it in write mode with UTF-8 encoding.

		This effectively empties the file if it exists, or creates a new empty file.

		Args:
			filename (str): Path to the file to reset.
		"""
		f = codecs.open(filename, "w", "utf8")
		f.close()

	@staticmethod
	def write_file(filename, separator, data, mode):
		"""
		Write data to a CSV file
		:param filename: the path+filename of the CSV file to read
		:param separator: the separator used in the CSV file
		:param data: array of array of the data to write
		:param mode: the mode we want to open the file in
		:return: None
		"""
		f = codecs.open(filename, mode, "utf8")
		for d in data:
			line = ""
			for index in range(len(d)):
				try:
					if d[index] is not None:
						line += str(d[index])
					else:
						line += ""
				except (UnicodeDecodeError, UnicodeEncodeError):
					line += unicodedata.normalize("NFKD", d[index]).encode(
						"ascii", errors="ignore"
					)
				if index < len(d) - 1:
					line += separator
			f.write(line + "\n")
		f.close()
