# src/ctf/utils.py
# basic utilities

import toml
from pathlib import Path
from platformdirs import user_config_dir
# Parse the config file, returning a config dictionary with relevant config options


# Load the config from file and parse with TOML
def load_config(config = f"{user_config_dir()}/ctf-config.toml") -> dict:
    p = Path(config)
    if p.exists():
        return toml.load(p)
    return{}

# Write a dictionary to the config file
def write_config(data: dict, config = f"{user_config_dir()}/ctf"):
    with open(config, "w") as f:
        toml.dump(data, f)

# return a list of path objects for each catagory in a competition
def active_categories(p: Path) -> list:
    cats = []
    if not p.exists(): return []
    for cat in p.iterdir():
        cats.append(cat)
    return cats

#return a lsit of Path objects of competitions in the base directory 
def active_competitions(dir: str) -> dict:
    comps = {}
    p = Path(dir)
    if not p.exists(): return {}
    for item in p.iterdir():
        if item.name == "tools": continue
        comps[item] = active_categories(item)
        print(item.name)
        print(comps[item])
    return comps

# {{{ suggest_patterns
def suggest_patterns(s: str, comp_name: str = "") -> list[str]:
    """Suggests a list of regex patterns from a sample flag string, optionally incorporating the competition name."""
    if not s or not s.strip():
        raise ValueError("Input string cannot be empty or whitespace only.")
        
    def get_type(c):
        if c.isupper():
            return 'U'
        elif c.islower():
            return 'L'
        elif c.isdigit():
            return 'D'
        else:
            return 'S'

    groups = []
    comp_idx = -1
    matched_prefix = ""
    if comp_name and comp_name.strip():
        comp_idx = s.lower().find(comp_name.lower())
        
    if comp_idx != -1:
        matched_prefix = s[comp_idx : comp_idx + len(comp_name)]
        # Parse prefix before competition name
        prefix_part = s[:comp_idx]
        if prefix_part:
            current_type = None
            current_chars = []
            for c in prefix_part:
                ctype = get_type(c)
                if ctype != current_type:
                    if current_type is not None:
                        groups.append((current_type, "".join(current_chars)))
                    current_type = ctype
                    current_chars = [c]
                else:
                    current_chars.append(c)
            if current_type is not None:
                groups.append((current_type, "".join(current_chars)))
                
        # Insert competition name group
        groups.append(('C', matched_prefix))
        
        # Parse suffix after competition name
        suffix_part = s[comp_idx + len(comp_name):]
        if suffix_part:
            current_type = None
            current_chars = []
            for c in suffix_part:
                ctype = get_type(c)
                if ctype != current_type:
                    if current_type is not None:
                        groups.append((current_type, "".join(current_chars)))
                    current_type = ctype
                    current_chars = [c]
                else:
                    current_chars.append(c)
            if current_type is not None:
                groups.append((current_type, "".join(current_chars)))
    else:
        # Normal grouping without competition name
        current_type = None
        current_chars = []
        for c in s:
            ctype = get_type(c)
            if ctype != current_type:
                if current_type is not None:
                    groups.append((current_type, "".join(current_chars)))
                current_type = ctype
                current_chars = [c]
            else:
                current_chars.append(c)
        if current_type is not None:
            groups.append((current_type, "".join(current_chars)))
            
    def escape_special(chars):
        res = []
        for c in chars:
            if c in r".+*?^$()[]{}|\/":
                res.append("\\" + c)
            else:
                res.append(c)
        return "".join(res)
        
    def build_pat(use_counts=True, merge_case=False):
        parts = []
        for gtype, gchars in groups:
            if gtype == 'C':
                parts.append(escape_special(gchars))
            elif gtype == 'U':
                if merge_case:
                    parts.append(f"[A-Za-z]{{{len(gchars)}}}" if use_counts else "[A-Za-z]+")
                else:
                    parts.append(f"[A-Z]{{{len(gchars)}}}" if use_counts else "[A-Z]+")
            elif gtype == 'L':
                if merge_case:
                    parts.append(f"[A-Za-z]{{{len(gchars)}}}" if use_counts else "[A-Za-z]+")
                else:
                    parts.append(f"[a-z]{{{len(gchars)}}}" if use_counts else "[a-z]+")
            elif gtype == 'D':
                parts.append(f"\\d{{{len(gchars)}}}" if use_counts else "\\d+")
            else:
                parts.append(escape_special(gchars))
        return "".join(parts)

    candidates = []
    
    # 1. Unanchored patterns (ideal for searching/scanning)
    candidates.append(build_pat(use_counts=True, merge_case=False))
    candidates.append(build_pat(use_counts=False, merge_case=False))
    candidates.append(build_pat(use_counts=True, merge_case=True))
    candidates.append(build_pat(use_counts=False, merge_case=True))
    
    # Custom character class
    unique_specials = set()
    has_alpha = False
    has_digit = False
    for c in s:
        if c.isalnum():
            if c.isalpha():
                has_alpha = True
            if c.isdigit():
                has_digit = True
        else:
            unique_specials.add(c)
    char_class_parts = []
    if has_alpha:
        char_class_parts.append("A-Za-z")
    if has_digit:
        char_class_parts.append("0-9")
    for spec in sorted(unique_specials):
        if spec in r"-[]\^$":
            char_class_parts.append("\\" + spec)
        else:
            char_class_parts.append(spec)
    candidates.append(f"[{''.join(char_class_parts)}]+")
    candidates.append(escape_special(s))
    
    # Wildcard patterns with .* and .*? (unanchored)
    if comp_idx == 0:
        suffix_part = s[len(comp_name):]
        esc_prefix = escape_special(matched_prefix)
        if suffix_part.startswith("{") and suffix_part.endswith("}"):
            candidates.append(f"{esc_prefix}\\{{.*\\}}")
            candidates.append(f"{esc_prefix}\\{{.*?\\}}")
            candidates.append(f"{esc_prefix}\\{{[^}}]*\\}}")
            candidates.append(f"{esc_prefix}\\{{[A-Za-z0-9_\\-]+\\}}")
            inner_content = suffix_part[1:-1]
            if all(c.islower() or c.isdigit() or c == '_' for c in inner_content):
                candidates.append(f"{esc_prefix}\\{{[a-z0-9_]+\\}}")
        else:
            candidates.append(f"{esc_prefix}.*")
            candidates.append(f"{esc_prefix}.*?")
    else:
        candidates.append(".*")
        candidates.append(".*?")

    # 2. Anchored versions of the above (ideal for strict validation)
    anchored_candidates = []
    for cand in candidates:
        anchored_candidates.append(f"^{cand}$")
    candidates.extend(anchored_candidates)
    
    # Deduplicate while preserving order
    seen = set()
    result = []
    for c in candidates:
        if c not in seen:
            seen.add(c)
            result.append(c)
    return result
# }}}

# Load variables to export
config = load_config("/home/venus/code/ctf/config.toml")
competition = config["Competition"]
enviroment = config["Enviroment"]
# base_dir = config["ctf_dir"]


