# Xjustiz2PDF is a desktop application that converts German xJustiz 
# e‑files (E-Akte) into a single PDF document
# Copyright (C) 2025 Björn Seipel
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

"""
pdfbuilder_selection.py – Auswahl-/Filterlogik
"""

from typing import Callable, List, Tuple, Optional
from PySide6.QtCore import Qt
from .parser import DocNode
from .utils import debug


def build_state_accessor(check_states: dict[str, int], disabled_paths: set[str]) -> Callable[[Optional[str]], int]:
    """
    Liefert eine Funktion, die für einen gegebenen Pfad den CheckState zurückgibt.
    - disabled_paths werden immer als Unchecked behandelt.
    - Wenn der Pfad nicht im Dict existiert, wird Unchecked zurückgegeben.
    """
    def state_for_path(path: Optional[str]) -> int:
        if path and path in disabled_paths:
            debug(f"[StateAccessor] path='{path}' ist disabled → Unchecked")
            return Qt.Unchecked
        state = check_states.get(path or "", Qt.Unchecked)
        debug(f"[StateAccessor] path='{path}' → state={state}, keys_sample={list(check_states.keys())[:5]}")
        return state
    return state_for_path


def get_root_docs_and_state(root: DocNode, state_for_path: Callable[[Optional[str]], int]) -> Tuple[List[DocNode], int]:
    """
    Liefert die Root-Dokumente und den State für ROOT_DOCS.
    """
    root_docs = [ch for ch in root.children if ch.is_doc()]
    root_state = state_for_path("ROOT_DOCS")
    debug(f"[Selection] Root-Dokumente={len(root_docs)}, ROOT_DOCS State={root_state}")
    return root_docs, root_state


def collect_docs_flat(root: DocNode, state_for_path: Callable[[Optional[str]], int],
                      filter_terms: List[str], only_originals: bool) -> List[DocNode]:
    """
    Sammelt alle Dokumente für den flachen Outline-Modus.
    Nur Checked-Ordner liefern Dokumente, PartiallyChecked wird ignoriert.
    """
    selected: List[DocNode] = []

    def should_filter(doc: DocNode) -> bool:
        text = (doc.anzeigename or "") + " " + (doc.file_path or "")
        match_terms = any(term.lower() in text.lower() for term in filter_terms)
        match_originals = only_originals and doc.bestandteil_code not in ("001", "002")
        return match_terms or match_originals

    def walk(node: DocNode, path_here: str):
        state = state_for_path(path_here)
        debug(f"[Selection] Walk Folder={node.anzeigename}, Path={path_here}, State={state}")
        if node.is_folder():
            if state == Qt.Checked:
                for c in node.children:
                    if c.is_doc() and not should_filter(c):
                        debug(f"[Selection] Flach: Dokument übernommen {c.anzeigename}")
                        selected.append(c)
            for c in node.children:
                if c.is_folder():
                    child_path = f"{path_here}/{c.anzeigename or 'Akte'}" if path_here else (c.anzeigename or "Akte")
                    walk(c, child_path)

    for c in root.children:
        if c.is_folder():
            path = c.anzeigename or "Akte"
            walk(c, path)

    root_docs = [ch for ch in root.children if ch.is_doc()]
    root_state = state_for_path("ROOT_DOCS")
    debug(f"[Selection] Flach: ROOT_DOCS State={root_state}, RootDocs={len(root_docs)}")
    if root_docs and root_state == Qt.Checked:
        for doc in root_docs:
            if not should_filter(doc):
                debug(f"[Selection] Flach: Root-Dokument übernommen {doc.anzeigename}")
                selected.append(doc)

    debug(f"[Selection] Flach gesammelt: {len(selected)} Dokumente")
    return selected
