"""Datenmodell und einzige Quelle der Wahrheit fuer das CSV-/BSDF-Schema.

Die Spaltenreihenfolge, die Attributnamen und die Zuordnung zu den Principled-BSDF
-Eingaengen werden ausschliesslich hier in ``FIELDS`` definiert. ``csv_io`` und die
Operatoren leiten Lesen, Schreiben und Validierung daraus ab, damit das Format nicht
mehr zwischen den drei Codepfaden auseinanderlaufen kann (frueher dreifach gepflegt).
"""

import csv
import os


class Field:
    """Beschreibt genau eine CSV-Spalte und ggf. ihren BSDF-Eingang.

    kind:
        'str'   -> wird unveraendert uebernommen (Category / Name)
        'float' -> einzelner Gleitkommawert
        'vec'   -> komma-getrennte Floats; ``components`` = Anzahl zu schreibender Werte
    """

    __slots__ = ("header", "attr", "bsdf_input", "kind", "components")

    def __init__(self, header, attr, bsdf_input, kind, components=0):
        self.header = header
        self.attr = attr
        self.bsdf_input = bsdf_input
        self.kind = kind
        self.components = components


FIELDS = [
    Field("Category", "category", None, "str"),
    Field("Name", "name", None, "str"),
    Field("Base Color", "base_color", "Base Color", "vec", 4),
    Field("Metallic", "metallic", "Metallic", "float"),
    Field("Roughness", "roughness", "Roughness", "float"),  # Sonderfall: AddRoughness-Node
    Field("IOR", "ior", "IOR", "float"),
    Field("Alpha", "alpha", "Alpha", "float"),
    Field("Subsurface Weight", "subsurface_weight", "Subsurface Weight", "float"),
    Field("Subsurface Radius", "subsurface_radius", "Subsurface Radius", "vec", 3),
    Field("Subsurface Scale", "subsurface_scale", "Subsurface Scale", "float"),
    Field("Subsurface Anisotropy", "subsurface_anisotropy", "Subsurface Anisotropy", "float"),
    Field("Specular IOR Level", "specular_ior", "Specular IOR Level", "float"),
    Field("Specular Tint", "specular_tint", "Specular Tint", "vec", 4),
    Field("Anisotropic", "anisotropic", "Anisotropic", "float"),
    Field("Anisotropic Rotation", "anisotropic_rotation", "Anisotropic Rotation", "float"),
    Field("Transmission Weight", "transmission_weight", "Transmission Weight", "float"),
    Field("Coat Weight", "coat_weight", "Coat Weight", "float"),
    Field("Coat Roughness", "coat_roughness", "Coat Roughness", "float"),
    Field("Coat IOR", "coat_ior", "Coat IOR", "float"),
    Field("Coat Tint", "coat_tint", "Coat Tint", "vec", 4),
    Field("Sheen Weight", "sheen_weight", "Sheen Weight", "float"),
    Field("Sheen Roughness", "sheen_roughness", "Sheen Roughness", "float"),
    Field("Sheen Tint", "sheen_tint", "Sheen Tint", "vec", 4),
    Field("Emission Color", "emission_color", "Emission Color", "vec", 4),
    Field("Emission Strength", "emission_strength", "Emission Strength", "float"),
    Field("Thin Film Thickness", "thin_film_thickness", "Thin Film Thickness", "float"),
    Field("Thin Film IOR", "thin_film_ior", "Thin Film IOR", "float"),
]

HEADERS = [f.header for f in FIELDS]
COLUMN_COUNT = len(FIELDS)  # 27


class Material:
    """Eine Zeile aus der CSV in typisierter Form."""

    def __init__(self, row):
        for field, raw in zip(FIELDS, row):
            value = raw.strip()
            if field.kind == "float":
                setattr(self, field.attr, float(value))
            elif field.kind == "vec":
                setattr(self, field.attr, tuple(float(v) for v in value.split(",")))
            else:
                setattr(self, field.attr, value)


class MaterialManager:
    """Haelt die geladene Bibliothek und sammelt Parse-Fehler fuer die UI."""

    def __init__(self):
        self.material_data = []
        self.errors = []  # menschenlesbare Fehlermeldungen, werden im Panel angezeigt
        self.zuletzt_migriert = None  # von csv_io.reload gesetzt (v1.4-Migration)

    def load_material_data(self, file_path):
        self.material_data.clear()
        self.errors.clear()
        if not os.path.exists(file_path):
            msg = f"CSV nicht gefunden: {file_path}"
            self.errors.append(msg)
            print(msg)
            return
        with open(file_path, newline="", encoding="utf-8") as csvfile:
            reader = csv.reader(csvfile)
            next(reader, None)  # Kopfzeile ueberspringen
            for line_no, row in enumerate(reader, start=2):
                if not row:
                    continue
                if len(row) < COLUMN_COUNT:
                    self.errors.append(
                        f"Zeile {line_no}: {len(row)} statt {COLUMN_COUNT} Spalten"
                    )
                    continue
                try:
                    self.material_data.append(Material(row[:COLUMN_COUNT]))
                except (ValueError, TypeError) as exc:
                    label = row[1] if len(row) > 1 else "?"
                    self.errors.append(f"Zeile {line_no} ({label}): {exc}")
        print(f"Loaded materials: {len(self.material_data)}")
        if self.errors:
            print(f"CSV-Fehler: {len(self.errors)}")


# Singleton, von allen Modulen gemeinsam genutzt.
material_manager = MaterialManager()
