import logging
from pathlib import Path

from valve_parsers import PCFFile, VPKFile

from core.handlers.pcf_handler import get_parent_elements

log = logging.getLogger()


def pcf_empty_root_processor():
    def process_pcf(pcf: PCFFile) -> PCFFile:
        root_element = pcf.elements[0]
        attr_type, _ = root_element.attributes[b'particleSystemDefinitions']
        root_element.attributes[b'particleSystemDefinitions'] = (attr_type, [])
        return pcf

    return process_pcf


def find_pos(data, val) -> int:
    count = 0
    val_len = len(val)
    pos = 0
    while True:
        pos = data.find(val, pos)
        if pos == -1:
            break
        data[pos:pos + val_len] = b' ' * val_len
        count += 1
        pos += val_len
    return count


def game_type(file_path: Path, uninstall: bool = False) -> bool:
    with file_path.open('r') as file:
        lines = file.readlines()

    found = False
    for i, line in enumerate(lines):
        if 'type' in line and 'multiplayer_only' in line:
            if uninstall and '//' in line:
                # remove the comment
                lines[i] = line.replace('//', '', 1)
                found = True
            elif not uninstall and '//' not in line:
                # add comment
                lines[i] = line.replace('type', '//type', 1)
                found = True

    if found:
        with file_path.open('w') as file:
            file.writelines(lines)
        return True
    else:
        return False


def check_game_type(file_path: Path) -> bool:
    try:
        with file_path.open('r') as file:
            for line in file:
                if 'type' in line and 'multiplayer_only' in line and '//' in line:
                    return True
        return False
    except Exception:
        log.exception(f"Error checking game type in {file_path}")
        return False


def should_process_file(file_path: str) -> bool:
    target_paths = [
        "materials/effects/",
        "materials/models/",
        "materials/particle/",
        "materials/particles/",
        "materials/prediction/",
        "materials/sprites/healbeam"
    ]

    path_lower = file_path.lower()
    return any(path in path_lower for path in target_paths) and path_lower.endswith('.vmt')


def initialize_pcf(dir: Path) -> tuple[PCFFile, set[str]]:
    default_base_path = dir / 'disguise.pcf'

    if not default_base_path.exists():
        raise FileNotFoundError(
            f"Vanilla particle staging folder is missing files:\n{dir}\n\n"
            "The folder was populated at startup but is missing files now. "
            "Something modified it during this session, try restarting the "
            "preloader, and check that antivirus or sync software isn't "
            "interfering with the temp folder."
        )

    default_base_pcf = PCFFile(default_base_path).decode()
    return default_base_pcf, get_parent_elements(default_base_pcf)


get_val = [
    [34, 36, 105, 103, 110, 111, 114, 101, 122, 34, 9, 34, 49, 34],
    [34, 36, 105, 103, 110, 111, 114, 101, 122, 34, 9, 49],
    [36, 105, 103, 110, 111, 114, 101, 122, 9, 34, 49, 34],
    [36, 105, 103, 110, 111, 114, 101, 122, 9, 49],
    [34, 36, 105, 103, 110, 111, 114, 101, 122, 34, 32, 34, 49, 34],
    [34, 36, 105, 103, 110, 111, 114, 101, 122, 34, 32, 49],
    [36, 105, 103, 110, 111, 114, 101, 122, 32, 34, 49, 34],
    [36, 105, 103, 110, 111, 114, 101, 122, 32, 49]]


def get_from_vpk(vpk_path: Path):
    try:
        # check if VPK contains target paths before processing
        vpk_handler = VPKFile(vpk_path)
        file_list = vpk_handler.list_files()
        should_process = any(should_process_file(file) for file in file_list)

        if should_process:
            # process entire VPK
            with open(vpk_path, 'rb') as vpk_f:
                data = bytearray(vpk_f.read())
                total = 0
                for val in get_val:
                    placements = find_pos(data, bytes(val))
                    if placements > 0:
                        total += placements
                if total > 0:
                    with open(vpk_path, 'wb') as f:
                        f.write(data)
    except Exception:
        log.exception(f"Error processing VPK {vpk_path}")


def get_from_file(file_path: Path):
    # lol. lmao, even
    try:
        with open(file_path, 'rb') as f:
            data = bytearray(f.read())
            total = 0
            for val in get_val:
                placements = find_pos(data, bytes(val))
                if placements > 0:
                    total += placements
            if total > 0:
                with open(file_path, 'wb') as f:
                    f.write(data)
            return total
    except Exception:
        log.exception(f"Error processing file {file_path}")
        return 0


def get_from_custom_dir(custom_dir: Path):
    if not custom_dir.exists():
        return 0

    # process VPK files
    for vpk_file in custom_dir.glob("*.vpk"):
        get_from_vpk(vpk_file)

    target_paths = [
        "materials/effects/",
        "materials/models/",
        "materials/particle/",
        "materials/particles/",
        "materials/prediction/",
        "materials/sprites/healbeam"
    ]

    for directory in custom_dir.glob("*"):
        if directory.is_dir():
            for file_path in directory.glob("**/*"):
                if file_path.is_file():
                    rel_path = str(file_path.relative_to(directory)).replace('\\', '/')
                    if any(rel_path.startswith(target) for target in target_paths):
                        get_from_file(file_path)
