import os
import re
import hashlib
from pathlib import Path
from PIL import Image
import cairosvg

# Define paths
ROOT_DIR = Path(__file__).resolve().parent.parent
SVG_DIR = ROOT_DIR / "svg"
PNG_DIR = ROOT_DIR / "png"
WEBP_DIR = ROOT_DIR / "webp"

# Ensure the output folders exist
PNG_DIR.mkdir(parents=True, exist_ok=True)
WEBP_DIR.mkdir(parents=True, exist_ok=True)

# Track results
failed_files = []
converted_pngs = 0
converted_webps = 0
total_icons = 0

def file_size_readable(size_bytes):
    """Convert bytes to a human-readable format."""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if size_bytes < 1024:
            return f"{size_bytes:.2f} {unit}"
            #size_bytes /= 1024
        size_bytes /= 1024
    return f"{size_bytes:.2f} TB"

def hash_file(file_path):
    """Generate an MD5 hash for a file."""
    hash_md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

def convert_to_kebab_case(name):
    """Convert a filename to kebab-case."""
    cleaned = re.sub(r'[^a-zA-Z0-9\s-]', '', name)
    kebab_case_name = re.sub(r'[\s_]+', '-', cleaned).lower()
    return kebab_case_name

def rename_if_needed(file_path):
    """Ensure the filename is in kebab-case; rename if necessary."""
    new_name = convert_to_kebab_case(file_path.stem) + file_path.suffix
    new_path = file_path.parent / new_name

    if new_path != file_path:
        if new_path.exists():
            raise FileExistsError(f"File conflict: {new_path} already exists.")
        file_path.rename(new_path)
        print(f"Renamed: {file_path} -> {new_path}")

    return new_path

def needs_conversion(output_file, data=None):
    """Check if a file needs to be converted or overwritten."""
    if output_file.exists():
        if data:
            existing_hash = hash_file(output_file)
            new_hash = hashlib.md5(data).hexdigest()
            return existing_hash != new_hash
        return False
    return True

def convert_svg_to_png(svg_path, png_path):
    """Convert SVG to PNG."""
    global converted_pngs
    try:
        png_data = cairosvg.svg2png(url=str(svg_path), output_height=512)

        if needs_conversion(png_path, png_data):
            with open(png_path, 'wb') as f:
                f.write(png_data)
            print(f"Converted PNG: {png_path} ({file_size_readable(png_path.stat().st_size)})")
            converted_pngs += 1
        else:
            print(f"PNG already up-to-date: {png_path}")

    except Exception as e:
        print(f"Failed to convert {svg_path} to PNG: {e}")
        failed_files.append(svg_path)

def convert_image_to_webp(image_path, webp_path):
    """Convert an image (PNG or other) to WEBP."""
    global converted_webps
    try:
        image = Image.open(image_path).convert("RGBA")

        if needs_conversion(webp_path):
            image.save(webp_path, format='WEBP')
            print(f"Converted WEBP: {webp_path} ({file_size_readable(webp_path.stat().st_size)})")
            converted_webps += 1
        else:
            print(f"WEBP already up-to-date: {webp_path}")

    except Exception as e:
        print(f"Failed to convert {image_path} to WEBP: {e}")
        failed_files.append(image_path)

def clean_up_files(folder, valid_basenames):
    """Remove files that no longer have corresponding SVG or PNG files."""
    removed_files = 0
    for file_path in folder.glob('*'):
        if file_path.stem not in valid_basenames:
            file_path.unlink()
            print(f"Removed: {file_path}")
            removed_files += 1
    return removed_files

if __name__ == "__main__":
    # Track valid basenames (from SVG and PNG files)
    valid_basenames = set()

    # Process all SVG files
    for svg_file in SVG_DIR.glob("*.svg"):
        total_icons += 1

        # Ensure the filename is in kebab-case
        try:
            svg_path = rename_if_needed(svg_file)
        except Exception as e:
            print(f"Error renaming {svg_file}: {e}")
            failed_files.append(svg_file)
            continue

        valid_basenames.add(svg_path.stem)

        # Set paths for PNG and WEBP
        png_path = PNG_DIR / f"{svg_path.stem}.png"
        webp_path = WEBP_DIR / f"{svg_path.stem}.webp"

        # Convert SVG to PNG
        convert_svg_to_png(svg_path, png_path)

        # Convert PNG to WEBP
        if png_path.exists():
            convert_image_to_webp(png_path, webp_path)

    # Process PNG-only files
    for png_file in PNG_DIR.glob("*.png"):
        if png_file.stem not in valid_basenames:
            # Ensure the filename is in kebab-case
            try:
                png_path = rename_if_needed(png_file)
            except Exception as e:
                print(f"Error renaming {png_file}: {e}")
                failed_files.append(png_file)
                continue

            valid_basenames.add(png_path.stem)

            # Set path for WEBP
            webp_path = WEBP_DIR / f"{png_path.stem}.webp"

            # Convert PNG to WEBP
            convert_image_to_webp(png_path, webp_path)

    # Clean up unused files in PNG and WEBP directories
    # Only remove files that don't have corresponding SVG or PNG files
    removed_pngs = clean_up_files(PNG_DIR, valid_basenames.union({p.stem for p in SVG_DIR.glob("*.svg")}))
    removed_webps = clean_up_files(WEBP_DIR, valid_basenames)

    # Display summary
    if converted_pngs == 0 and converted_webps == 0 and removed_pngs == 0 and removed_webps == 0:
        print("\nAll icons are already up-to-date.")
    else:
        print(f"\nConverted {converted_pngs} PNGs and {converted_webps} WEBPs out of {total_icons} icons.")
        print(f"Removed {removed_pngs} PNGs and {removed_webps} WEBPs.")

    # Display any failed conversions
    if failed_files:
        print("\nThe following files failed to convert:")
        for file in failed_files:
            print(file)