"""
Bronze – {{ title }}
{{ '=' * (title | length + 9) }}
{{ description }}

Source: {{ source_name }} ({{ source_system }})
Extraction mode: LLM-powered unstructured data parsing.

Called by lakelogic via external_logic in {{ contract_filename }}.
Generated by Zeus AI from template: bronze_unstructured_processor.
"""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Optional, Dict, Any

import polars as pl


def run(
    good_df,
    *,
    contract=None,
    engine: str = "polars",
    **_kwargs,
):
    """
    LakeLogic external_logic entrypoint — Unstructured Extraction.

    Processes raw unstructured data (PDFs, text, images) and extracts
    structured fields using LLM-based extraction rules defined in the
    contract's extraction block.

    Parameters
    ----------
    good_df : DataFrame
        Raw records containing unstructured content (e.g. raw_text, file_path columns).
    """
    # ── Coerce to Polars ──────────────────────────────────────────────────
    df = _to_polars(good_df)

    # ── Extraction placeholder ────────────────────────────────────────────
    # The extraction logic is driven by the contract YAML's `extraction` block.
    # LakeLogic's runtime reads the extraction.fields and extraction.model config
    # and applies LLM-based parsing before this processor runs.
    #
    # This processor handles any post-extraction transformations:
{%- if post_extraction_steps %}
{% for step in post_extraction_steps %}
    # {{ step.description }}
    df = df.with_columns(
        {{ step.expression }}.alias("{{ step.output_field }}"),
    )
{% endfor %}
{%- endif %}

    # ── Add audit/metadata columns ────────────────────────────────────────
    df = df.with_columns(
        pl.lit(datetime.now(timezone.utc).replace(microsecond=0)).alias("_bronze_loaded_at"),
        pl.lit("{{ source_system }}").alias("_source_system"),
        pl.lit("llm_extraction").alias("_extraction_method"),
    )

    return _maybe_to_spark(df, engine)


# ── Helpers ───────────────────────────────────────────────────────────────────


def _to_polars(df) -> pl.DataFrame:
    """Convert any DataFrame to Polars."""
    if isinstance(df, pl.DataFrame):
        return df
    if hasattr(df, "toPandas"):
        return pl.from_pandas(df.toPandas())
    return pl.from_pandas(df)


def _maybe_to_spark(df: pl.DataFrame, engine: str):
    """Convert back to Spark if needed."""
    if engine == "spark":
        try:
            from pyspark.sql import SparkSession
            spark = SparkSession.builder.getOrCreate()
            return spark.createDataFrame(df.to_pandas())
        except Exception:
            pass
    return df
