import os
import re
import shutil
from pathlib import Path
from pypdf import PdfReader
from docx import Document
from pptx import Presentation
from openpyxl import load_workbook

from helpers.ConfigHelper import is_windows, get_config


def build_conflicted_regex(filename):
    if "." in filename:
        # TODO: improve this for complex filenames
        namepart = filename.split(".")[0]
        extpart = filename.split(".")[1]
        # pylint: disable=anomalous-backslash-in-string
        return rf"{namepart} \(conflicted copy \d{{4}}-\d{{2}}-\d{{2}} \d{{6}}\)\.{extpart}"
    # pylint: disable=anomalous-backslash-in-string
    return rf"{filename} \(conflicted copy \d{{4}}-\d{{2}}-\d{{2}} \d{{6}}\)"


def sanitize_path(path):
    return path.replace("//", "/")


def prefix_path_namespace(path):
    if is_windows():
        # https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#win32-file-namespaces
        # disable string parsing
        #  - long path
        #  - trailing whitespaces
        return f"\\\\?\\{path}"
    return path


def can_read(resource):
    read = False
    try:
        with open(resource, encoding="utf-8") as f:
            read = True
    except:
        pass
    return read and os.access(resource, os.R_OK)


def can_write(resource):
    write = False
    try:
        with open(resource, "w", encoding="utf-8") as f:
            write = True
    except:
        pass
    return write and os.access(resource, os.W_OK)


def read_file_content(file):
    with open(file, "r", encoding="utf-8") as f:
        content = f.read()
    return content


def is_empty_sync_folder(folder):
    ignore_files = ["Desktop.ini"]
    for item in os.listdir(folder):
        # do not count the hidden files as they are ignored by the client
        if not item.startswith(".") and not item in ignore_files:
            return False
    return True


def get_size_in_bytes(size):
    match = re.match(r"(\d+)((?: )?[KkMmGgBb]{0,2})?", str(size))
    units = ["b", "kb", "mb", "gb"]
    multiplier = 1024
    if match:
        size_num = int(match.group(1))
        size_unit = match.group(2)

        if not (size_unit := size_unit.lower()):
            return size_num
        if size_unit in units:
            if size_unit == "b":
                return size_num
            if size_unit == "kb":
                return size_num * multiplier
            if size_unit == "mb":
                return size_num * (multiplier**2)
            if size_unit == "gb":
                return size_num * (multiplier**3)

    raise ValueError("Invalid size: " + size)


def get_file_size(resource_path):
    return os.stat(resource_path).st_size


# temp paths created outside the temporary directory during the test
CREATED_PATHS = []


def remember_path(path):
    CREATED_PATHS.append(path)


def cleanup_created_paths():
    global CREATED_PATHS
    for path in CREATED_PATHS:
        if os.path.exists(path):
            if os.path.isdir(path):
                shutil.rmtree(prefix_path_namespace(path))
            else:
                os.unlink(prefix_path_namespace(path))
    CREATED_PATHS = []


def get_file_for_upload(file_name):
    base_upload_dir = get_config("files_for_upload")
    return os.path.join(base_upload_dir, file_name)


def convert_path_separators_for_os(path):
    """
    Convert path separators to match the current operating system.
    On Windows, converts forward slashes to backslashes.
    On other systems, returns the path unchanged.
    """
    if is_windows():
        return path.replace("/", "\\")
    return path


def get_pdf_content(pdf_file):
    reader = PdfReader(pdf_file)
    content = ""
    for page in reader.pages:
        if page_text := page.extract_text():
            content += page_text
    return content


def get_docs_content(docs_file):
    doc = Document(docs_file)
    content = "\n".join(p.text for p in doc.paragraphs)
    return content


def get_presentation_content(ppt_file):
    presentation = Presentation(ppt_file)
    text = []
    for slide in presentation.slides:
        for shape in slide.shapes:
            if hasattr(shape, "text"):
                text.append(shape.text)
    return "\n".join(text)


def get_excel_content(excel_file):
    # parse with read_only mode
    workbook = load_workbook(excel_file, read_only=True, data_only=True)
    text = []
    for sheet in workbook.worksheets:
        for row in sheet.iter_rows(values_only=True):
            for cell in row:
                if cell is not None:
                    text.append(str(cell))
    return "\n".join(text)


def get_document_content(document):
    content = ""
    doc_ext = Path(document).suffix.lower().lstrip(".")
    if doc_ext == "pdf":
        content = get_pdf_content(document)
    elif doc_ext == "docx":
        content = get_docs_content(document)
    elif doc_ext == "pptx":
        content = get_presentation_content(document)
    elif doc_ext == "xlsx":
        content = get_excel_content(document)
    elif doc_ext in ["txt", "md"]:
        with open(document, "r", encoding="utf-8") as f:
            content = f.read()
    else:
        raise ValueError(f"Unsupported document format: {doc_ext}")
    return content
