import os
from pathlib import Path

import typer

ROOT_FOLDER = "/home/kodjo/Dev/MyDocManager/src/frontend/node_modules/@sicons"
MAX_SIZE = 2000000

import re


def pascal_to_snake(name: str) -> str:
  """Convert a PascalCase or CamelCase string to snake_case."""
  if name is None:
    return None
  
  name = name.strip()
  # Insert underscore before capital letters (except the first one)
  s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name)
  # Handle consecutive capital letters (like 'HTTPServer' -> 'http_server')
  s2 = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1)
  return s2.lower()


app = typer.Typer()


def list_sources(source_folder: str):
  return os.listdir(source_folder)


def list_icons_from_source(source_folder: str, source: str):
  res = []
  for f in os.listdir(f"{source_folder}/{source}"):
    if f.endswith(".svg"):
      res.append(f)
  return res


def read_content(source_folder: str, source: str, file_name: str):
  with open(f"{source_folder}/{source}/{file_name}", "r") as f:
    return f.read().strip()


def get_dir_size(path: str | Path) -> int:
  p = Path(path)
  if p.is_file():
    return p.stat().st_size
  elif p.is_dir():
    return sum(f.stat().st_size for f in p.rglob('*') if f.is_file())
  else:
    raise FileNotFoundError(f"Path not found: {path}")


def sizeof_fmt(num, suffix="B"):
  for unit in ["", "K", "M", "G", "T"]:
    if abs(num) < 1024.0:
      return f"{num:3.1f}{unit}{suffix}"
    num /= 1024.0
  return f"{num:.1f}P{suffix}"


def init_buffer(source_folder: str, source: str):
  buffer = ""
  readme_file_path = f"{source_folder}/{source}/README.md"
  if os.path.exists(readme_file_path):
    with open(readme_file_path, "r") as f_readme:
      for line in f_readme:
        if line.startswith("#"):
          buffer += line
        else:
          buffer += f"# {line}"
      buffer += "\n\n"
  
  buffer += "from fastcore.basics import NotStr\n\n"
  return buffer


def flush(dry_run, suppress_suffix, source_folder: str, target_folder: str, buffer: str, size: int, part: int, source: str):
  suffix = '' if suppress_suffix else f"_test"
  outfile = f"{source}{suffix}.py" if part == 0 else f"{source}_p{part}{suffix}.py"
  if not dry_run:
    output_path = f"{target_folder}/{outfile}" if part == 0 else f"{target_folder}/{outfile}"
    with open(output_path, "w") as f:
      f.write(buffer)
  
  typer.echo(f"  Generated {source} as {outfile} ({sizeof_fmt(size)}, max={sizeof_fmt(MAX_SIZE)})")
  return init_buffer(source_folder, source), 0, part + 1


@app.command("list")
def list_icons(
    source: str = typer.Argument(None, help="The source file to list icons from"),
    source_folder: str = typer.Option(ROOT_FOLDER, help="The source folder containing icons"),
    count: bool = typer.Option(False, help="Counts the number of items"),
    size: bool = typer.Option(False, help="Gets the size of the items"),
):
  res = []
  if source:
    res.extend(list_icons_from_source(source_folder, source))
  else:
    res.extend(list_sources(source_folder))
  
  if count:
    typer.echo(len(res))
    return
  
  if size:
    path = f"{source_folder}/{source}" if source else f"{source_folder}"
    size = get_dir_size(path)
    typer.echo(sizeof_fmt(size))
    return
  
  for r in res:
    typer.echo(r)


@app.command("generate")
def generate_icons(
    source: str = typer.Argument(None, help="The source file to list icons from"),
    source_folder: str = typer.Option(ROOT_FOLDER, help="The source folder containing icons"),
    target_folder: str = typer.Option(".", help="The folder where to create the python files."),
    top: int = typer.Option(0, help="The number of top items to generate"),
    dry_run: bool = typer.Option(True, help="Does not generate the icons"),
    suppress_suffix: bool = typer.Option(False, help="Does not add the suffix to the icon names"),
):
  sources = [source] if source else list_sources(source_folder)
  for current_source in sources:
    typer.echo(f"Generating icons for {current_source}")
    buffer = init_buffer(source_folder, current_source)
    size = 0
    part = 0
    for index, svg_file in enumerate(list_icons_from_source(source_folder, current_source)):
      
      if 0 < top <= index:
        break
      
      icon_name = os.path.splitext(os.path.basename(svg_file))[0]
      svg_content = read_content(source_folder, current_source, svg_file)
      svg_content = svg_content.replace("<svg ", f'<svg name="{current_source}-{icon_name}" ').replace("\n", "")
      
      content = f"{pascal_to_snake(icon_name)} = NotStr('''{svg_content}''')"
      buffer += f"{content}\n"
      size += len(content)
      
      if size > MAX_SIZE:
        buffer, size, part = flush(dry_run, suppress_suffix, source_folder, target_folder, buffer, size, part,
                                   current_source)
    
    flush(dry_run, suppress_suffix, source_folder, target_folder, buffer, size, part, current_source)


if __name__ == "__main__":
  app()
