#!/usr/bin/env python3

import os
import shutil
import argparse
from bs4 import BeautifulSoup

# Function to recursively search for the "Source" directory
def find_source_dir(starting_path, source_dir):
    for root, dirs, files in os.walk(starting_path):
        if source_dir in dirs:
            source_path = os.path.join(root, source_dir)
            before_source = os.path.relpath(source_path, starting_path)
            after_source = os.path.relpath(starting_path, source_path)
            return before_source
    return None, None

def check_for_siblings(docs_root, source_dir):
    all_dirs = [os.path.join(docs_root, d) for d in os.listdir(docs_root) if os.path.isdir(os.path.join(docs_root, d))]
    if not os.path.exists(docs_root):
        return 1, None

    source_path = os.path.abspath(os.path.join(docs_root, source_dir))
    if not os.path.exists(source_path):
        return 2, all_dirs

    sibling_dirs = [d for d in all_dirs if not os.path.samefile(d, source_path)]

    if sibling_dirs:
        return 3, sibling_dirs

    return 0, None

def has_files(path):
    for root, _, files in os.walk(path):
        if files:
            return True
    return False

def delete_empty_directory(relative_path):
    absolute_path = os.path.abspath(relative_path)
    if not os.path.exists(absolute_path):
        print(f"Directory does not exist: {relative_path}")
        return
    if has_files(absolute_path):
        print(f"Directory is not empty: {relative_path}")
        return
    try:
        shutil.rmtree(absolute_path)
        print(f"Deleted: {relative_path}")
    except OSError as e:
        print(f"Error deleting directory: {e}")

def remove_directory_if_exists(relative_path):
    absolute_path = os.path.abspath(relative_path)
    if os.path.exists(absolute_path) and os.path.isdir(absolute_path):
        try:
            shutil.rmtree(absolute_path)
            print(f"Removed directory and its contents: {relative_path}")
        except OSError as e:
            print(f"Error removing directory: {e}")
    else:
        print(f"Directory does not exist: {relative_path}")

def process_docs(source_dir, docs_root):
    # Define the path to the index.html file
    index_html_path = os.path.join(docs_root, "index.html")

    # Read the index.html file
    with open(index_html_path, "r") as html_file:
        index_html_content = html_file.read()
    html = BeautifulSoup(index_html_content, "html.parser")

    # Modify links and associated html files within each tr.light-row
    for tr in html.find_all("tr", class_="light-row"):
        link = tr.find("a", href=True)
        if link:
            href = link["href"]
            # Fix linked file title and css href
            filepath = os.path.join(docs_root, href)
            fix_code_html(filepath, source_dir)

            source_root_index = href.find(source_dir)
            if source_root_index != -1:
                trimmed_href = href[source_root_index:]
                link["href"] = f"coverage/{trimmed_href}"

    # Save the modified HTML content back to the index.html file
    with open(index_html_path, "w") as modified_html_file:
        modified_html_file.write(str(html))

def fix_code_html(path_filename, source_dir):
    with open(path_filename, "r") as html_file:
        html_content = html_file.read()
    html = BeautifulSoup(html_content, "html.parser")

    # fix css href
    link = html.find("link")
    css = link["href"].split('/')[-1]
    depth = path_filename.split("Source")[-1].count('/')
    parent_nav = "../" * (depth + 1)
    link["href"] = f"{parent_nav}{css}"

    # fix title
    title = html.select_one('.source-name-title pre')
    fixed_title = f".../{source_dir}{title.text.split(source_dir)[-1]}"
    title.string = fixed_title

    # resave
    with open(path_filename, "w") as html_file:
        html_file.write(str(html))

# Parse command line arguments
parser = argparse.ArgumentParser(description="Transmogrify a llvm-cov report to use relative paths to source.")
parser.add_argument("--source-dir", required=True, help="Name of Source directory within the report coverage/ path")
parser.add_argument("--docs-root", required=True, help="Path to the docs folder containing index.html and coverage/ path.")
args = parser.parse_args()

coverage_path = os.path.join(args.docs_root, "coverage")

status, dirs = check_for_siblings(coverage_path, args.source_dir)

if status == 1:
    print(f"{args.docs_root} does not exist.")
    exit(1)

if status == 3:
    remove_directory_if_exists(os.path.join(coverage_path, args.source_dir))

process_docs(args.source_dir, args.docs_root)
source_path = os.path.join(args.docs_root, "coverage", find_source_dir(coverage_path, args.source_dir))

shutil.move(source_path, coverage_path)

# We can assume the original folder tree starts
# with Users so we will delete that carefully
disgraced_former_cov_docs_path = os.path.join(coverage_path, "Users")

# Delete the original path, if it's tree is empty.
delete_empty_directory(disgraced_former_cov_docs_path)
