"""Filesystem walker — Phase 1: Structure.

Scans a project directory and discovers all source files,
building the folder/file tree structure.
"""

from __future__ import annotations

import os
from pathlib import Path

from ...config import settings
from ..models import EdgeType, FileNode, NodeType, SymbolNode, Edge
from ._console import console


def walk_project(root_path: str) -> tuple[list[FileNode], list[SymbolNode], list[Edge]]:
    """Walk a project directory and return file nodes + folder structure.

    Returns:
        (files, nodes, edges) — file metadata, folder/file nodes, CONTAINS edges
    """
    root = Path(root_path).resolve()
    if not root.is_dir():
        raise ValueError(f"Not a directory: {root}")

    files: list[FileNode] = []
    nodes: list[SymbolNode] = []
    edges: list[Edge] = []
    seen_folders: set[str] = set()

    ignored = set(settings.ignored_dirs)
    supported = settings.supported_extensions
    max_file_bytes = settings.max_file_size_kb * 1024

    for dirpath, dirnames, filenames in os.walk(root):
        # Filter ignored directories (modifying in place to skip recursion)
        dirnames[:] = [d for d in dirnames if d not in ignored and not d.startswith(".")]

        rel_dir = os.path.relpath(dirpath, root)
        if rel_dir == ".":
            rel_dir = ""

        # Create folder node
        if rel_dir and rel_dir not in seen_folders:
            folder_uid = f"folder:{rel_dir}"
            nodes.append(SymbolNode(
                uid=folder_uid,
                name=os.path.basename(dirpath),
                node_type=NodeType.FOLDER,
                file_path=rel_dir,
                line_start=0,
                line_end=0,
            ))
            seen_folders.add(rel_dir)

            # Parent folder edge
            parent_dir = os.path.dirname(rel_dir)
            if parent_dir:
                parent_uid = f"folder:{parent_dir}"
                edges.append(Edge(
                    source_uid=parent_uid,
                    target_uid=folder_uid,
                    edge_type=EdgeType.CONTAINS,
                ))

        for filename in filenames:
            ext = os.path.splitext(filename)[1].lower()
            if ext not in supported:
                continue

            filepath = os.path.join(dirpath, filename)
            rel_path = os.path.relpath(filepath, root).replace("\\", "/")

            try:
                size = os.path.getsize(filepath)
            except OSError:
                continue

            if size > max_file_bytes:
                continue

            language = supported[ext]
            file_node = FileNode(
                path=filepath,
                relative_path=rel_path,
                language=language,
                size_bytes=size,
            )
            files.append(file_node)

            # File node in graph
            file_uid = f"file:{rel_path}"
            nodes.append(SymbolNode(
                uid=file_uid,
                name=filename,
                node_type=NodeType.FILE,
                file_path=rel_path,
                line_start=0,
                line_end=0,
                language=language,
            ))

            # Folder -> File edge
            if rel_dir:
                folder_uid = f"folder:{rel_dir}"
                edges.append(Edge(
                    source_uid=folder_uid,
                    target_uid=file_uid,
                    edge_type=EdgeType.CONTAINS,
                ))

    console.print(f"  [green]✓[/green] Structure: {len(files)} files, {len(seen_folders)} folders")
    return files, nodes, edges
