"""Provide pipeline stub fragments and project files for Delta Live Tables."""

from __future__ import annotations

from textwrap import dedent
from typing import Callable, Mapping

from .. import PipelineFile, PipelineProject, PipelineStub, register_pipeline_stub


def _coerce_hint(hints: Mapping[str, object], key: str) -> str:
    value = hints.get(key)
    if value is None:
        return ""
    return str(value).strip()


def _dlt_readme(hints: Mapping[str, object]) -> str:
    workspace = _coerce_hint(hints, "dlt_workspace_url")
    profile = _coerce_hint(hints, "dlt_workspace_profile")
    pipeline_name = _coerce_hint(hints, "dlt_pipeline_name")
    notebook_path = _coerce_hint(hints, "dlt_notebook_path")
    target_schema = _coerce_hint(hints, "dlt_target_schema")

    wizard_hints = ["Wizard hints captured during export:"]
    if pipeline_name:
        wizard_hints.append(f"- Pipeline name: {pipeline_name}")
    if workspace:
        wizard_hints.append(f"- Workspace host: {workspace}")
    if profile:
        wizard_hints.append(f"- CLI profile: {profile}")
    if notebook_path:
        wizard_hints.append(f"- Notebook path: {notebook_path}")
    if target_schema:
        wizard_hints.append(f"- Target schema: {target_schema}")
    if len(wizard_hints) == 1:
        wizard_hints.append("- (no workspace hints were recorded)")

    return (
        dedent(
            """
            # Delta Live Tables pipeline example

            This directory contains a scaffold for a Delta Live Tables pipeline
            that applies contract expectations and dc43 governance hooks. The
            `pipeline.py` module defines bronze/silver/gold tables while
            `ops.py` demonstrates how to keep the dc43 services informed about
            pipeline activity.

            Update the constants in ``pipeline.py`` and ``ops.py`` before
            publishing the pipeline. Replace the sample transformations with
            your production logic once the integration is verified.
            """
        ).strip()
        + "\n\n"
        + "\n".join(wizard_hints)
        + "\n"
    )


def _dlt_pipeline_module() -> str:
    return dedent(
        '''
        """Delta Live Tables definitions generated by the dc43 setup wizard."""

        from __future__ import annotations

        import dlt
        from pyspark.sql import functions as F

        from bootstrap_pipeline import build_dlt_context, load_service_clients
        from dc43_integrations.spark.dlt import governed_expectations, governed_table


        CONTRACT_ID = "replace-with-contract-id"
        CONTRACT_VERSION = "replace-with-contract-version"
        SOURCE_TABLE = "replace-with-source-table"

        SUITE = load_service_clients()
        CONTEXT = build_dlt_context()
        GOVERNANCE_SERVICE = SUITE.governance


        @governed_table(
            dlt,
            context={
                "contract": {
                    "contract_id": CONTRACT_ID,
                    "contract_version": CONTRACT_VERSION,
                }
            },
            governance_service=GOVERNANCE_SERVICE,
            table_properties={"quality": "bronze"},
        )
        def bronze_contract_input():
            """Load the raw dataset governed by ``CONTRACT_ID``."""

            return spark.read.table(SOURCE_TABLE)  # type: ignore[name-defined]


        @dlt.table(comment="Validated dataset derived from the bronze layer.")
        @governed_expectations(
            dlt,
            context={
                "contract": {
                    "contract_id": CONTRACT_ID,
                    "contract_version": CONTRACT_VERSION,
                }
            },
            governance_service=GOVERNANCE_SERVICE,
        )
        def silver_contract_view():
            """Apply lightweight transformations that preserve the contract."""

            df = dlt.read("bronze_contract_input")
            return df.withColumn("processed_at", F.current_timestamp())


        @governed_table(
            dlt,
            name="gold_contract_output",
            context={
                "contract": {
                    "contract_id": CONTRACT_ID,
                    "contract_version": CONTRACT_VERSION,
                }
            },
            governance_service=GOVERNANCE_SERVICE,
            comment="Publish a gold table ready for downstream consumption.",
            table_properties={"quality": "gold"},
        )
        def gold_contract_output():
            df = dlt.read("silver_contract_view")
            if "is_valid" in df.columns:
                return df.filter(F.col("is_valid"))
            return df


        def pipeline_metadata() -> dict[str, object]:
            """Expose pipeline metadata for downstream automation."""

            return {
                "workspace": CONTEXT.get("workspace"),
                "pipeline_name": CONTEXT.get("pipeline_name"),
                "notebook_path": CONTEXT.get("notebook_path"),
                "target_schema": CONTEXT.get("target_schema"),
            }
        '''
    ).strip() + "\n"


def _dlt_ops_module() -> str:
    return dedent(
        '''
        """Operational helpers for the Delta Live Tables pipeline example."""

        from __future__ import annotations

        from typing import Any, Mapping


        def ensure_pipeline_registered(
            *,
            workspace,
            pipeline_name: str,
            notebook_path: str | None,
            target_schema: str | None,
        ) -> None:
            """Showcase how to prepare a Delta Live Tables pipeline via the API."""

            if workspace is None:
                print("[dlt] Workspace client unavailable; skip pipeline registration demo.")
                return

            print("[dlt] Pipeline registration example:")
            print("      workspace.pipelines.create_or_update(...) with")
            print("        name=", pipeline_name)
            if notebook_path:
                print("        notebook path=", notebook_path)
            if target_schema:
                print("        target schema=", target_schema)


        def register_output_port(
            *,
            data_product_backend,
            data_product_id: str,
            output_port: str,
            contract_id: str,
            contract_version: str,
        ) -> None:
            """Bind the gold table to the data-product service."""

            data_product_backend.register_output_port(
                data_product_id=data_product_id,
                port_name=output_port,
                contract_id=contract_id,
                contract_version=contract_version,
            )
            print(
                "[data_products] Registered output port",
                output_port,
                "for",
                data_product_id,
            )


        def publish_governance_updates(
            *,
            governance_store,
            dataset_id: str,
            dataset_version: str,
            contract_id: str,
            contract_version: str,
            status: str = "success",
        ) -> None:
            """Record the latest pipeline run in the governance store."""

            governance_store.link_dataset_contract(
                dataset_id=dataset_id,
                dataset_version=dataset_version,
                contract_id=contract_id,
                contract_version=contract_version,
            )
            governance_store.record_pipeline_event(
                dataset_id=dataset_id,
                dataset_version=dataset_version,
                contract_id=contract_id,
                contract_version=contract_version,
                event={"status": status},
            )


        def describe_context(context: Mapping[str, Any]) -> None:
            """Pretty-print context metadata returned by ``build_dlt_context``."""

            pipeline_name = context.get("pipeline_name") or "(not configured)"
            notebook_path = context.get("notebook_path") or "(not configured)"
            target_schema = context.get("target_schema") or "(not configured)"
            print("[dlt] Pipeline name:", pipeline_name)
            print("[dlt] Notebook path:", notebook_path)
            print("[dlt] Target schema:", target_schema)
        '''
    ).strip() + "\n"


def _dlt_project(hints: Mapping[str, object]) -> PipelineProject:
    return PipelineProject(
        root="dlt_pipeline",
        entrypoint="pipeline.py",
        files=(
            PipelineFile(path="README.md", content=_dlt_readme(hints)),
            PipelineFile(
                path="__init__.py",
                content='"""Delta Live Tables pipeline example package."""\n',
            ),
            PipelineFile(path="pipeline.py", content=_dlt_pipeline_module()),
            PipelineFile(path="ops.py", content=_dlt_ops_module()),
        ),
    )


def _dlt_pipeline_stub(
    *,
    hints: Mapping[str, object],
    flags: Mapping[str, bool],
    json_literal: Callable[[object | None], str],
) -> PipelineStub:
    workspace_hint = json_literal(hints.get("dlt_workspace_url"))
    profile_hint = json_literal(hints.get("dlt_workspace_profile"))
    pipeline_name = json_literal(hints.get("dlt_pipeline_name"))
    notebook_hint = json_literal(hints.get("dlt_notebook_path"))
    target_hint = json_literal(hints.get("dlt_target_schema"))
    contract_id = json_literal("replace-with-contract-id")
    contract_version = json_literal("replace-with-contract-version")
    dataset_id = json_literal("replace-with-data-product-id")
    dataset_version = json_literal("replace-with-dataset-version")
    output_port = json_literal("replace-with-output-port")

    main_lines = (
        "    if integration == 'dlt':",
        "        context = build_dlt_context()",
        "        workspace = context.get('workspace')",
        "        if workspace is not None:",
        "            print(\"[dlt] Workspace client initialised:\", workspace)",
        f"        workspace_hint = {workspace_hint}",
        "        if workspace_hint:",
        "            print(\"[dlt] Workspace host:\", workspace_hint)",
        f"        profile_hint = {profile_hint}",
        "        if profile_hint:",
        "            print(\"[dlt] CLI profile:\", profile_hint)",
        f"        pipeline_name = {pipeline_name}",
        "        if pipeline_name:",
        "            print(\"[dlt] Pipeline name:\", pipeline_name)",
        f"        notebook_hint = {notebook_hint}",
        "        if notebook_hint:",
        "            print(\"[dlt] Notebook path:\", notebook_hint)",
        f"        target_hint = {target_hint}",
        "        if target_hint:",
        "            print(\"[dlt] Target schema:\", target_hint)",
        "        contract_backend = context.get('contract_backend', contract_backend)",
        "        data_product_backend = context.get('data_product_backend', data_product_backend)",
        "        data_quality_backend = context.get('data_quality_backend', data_quality_backend)",
        "        governance_store = context.get('governance_store', governance_store)",
        f"        contract_id = {contract_id}",
        f"        contract_version = {contract_version}",
        f"        dataset_id = {dataset_id}",
        f"        dataset_version = {dataset_version}",
        f"        output_port = {output_port}",
        "        dlt_ops.describe_context(context)",
        "        dlt_ops.ensure_pipeline_registered(",
        "            workspace=workspace,",
        "            pipeline_name=pipeline_name or 'replace-with-dlt-pipeline',",
        "            notebook_path=context.get('notebook_path'),",
        "            target_schema=context.get('target_schema'),",
        "        )",
        "        dlt_ops.register_output_port(",
        "            data_product_backend=data_product_backend,",
        "            data_product_id=dataset_id,",
        "            output_port=output_port,",
        "            contract_id=contract_id,",
        "            contract_version=contract_version,",
        "        )",
        "        dlt_ops.publish_governance_updates(",
        "            governance_store=governance_store,",
        "            dataset_id=dataset_id,",
        "            dataset_version=dataset_version,",
        "            contract_id=contract_id,",
        "            contract_version=contract_version,",
        "        )",
    )

    tail_lines = (
        "    if integration == 'dlt':",
        "        print(\"[dlt] Review examples/dlt_pipeline for table definitions and ops.\")",
    )

    return PipelineStub(
        bootstrap_imports=("build_dlt_context",),
        additional_imports=("from dlt_pipeline import ops as dlt_ops",),
        main_lines=main_lines,
        tail_lines=tail_lines,
        project=_dlt_project(hints),
    )


register_pipeline_stub("dlt", _dlt_pipeline_stub)


__all__ = ["_dlt_pipeline_stub"]

