"""The change log records who edited a mix/ingredient and what changed.

Covers `record_change` / `diff_fields` / `list_changes`: edits are stored with a
field-level before/after diff and read back newest-first per entity.
"""
from __future__ import annotations

from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker

from app.api.deps import AuthSession
from app.db.session import Base
from app.services.change_log import (
    ENTITY_INGREDIENT,
    ENTITY_MIX,
    diff_fields,
    list_changes,
    record_change,
)

TENANT = "hunter-premium-produce"

LABELS = {"name": "Name", "kg_per_unit": "Kg per unit", "status": "Status"}


def _session() -> Session:
    engine = create_engine("sqlite:///:memory:")
    Base.metadata.create_all(bind=engine)
    return sessionmaker(bind=engine, expire_on_commit=False)()


def _actor() -> AuthSession:
    return AuthSession(role="internal", email="lara@hunter.test", name="Lara", tenant_id=TENANT, client_role="admin")


def test_diff_fields_only_emits_changed_keys():
    deltas = diff_fields({"name": "Maize", "kg_per_unit": 25.0}, {"name": "Maize", "kg_per_unit": 30.0}, LABELS)
    assert len(deltas) == 1
    assert deltas[0]["field"] == "kg_per_unit"
    assert deltas[0]["before"] == "25"
    assert deltas[0]["after"] == "30"


def test_records_and_lists_changes_newest_first():
    db = _session()
    session = _actor()

    record_change(
        db,
        session=session,
        entity_type=ENTITY_INGREDIENT,
        entity_id=7,
        action="created",
        summary="Created ingredient “Maize”",
    )
    record_change(
        db,
        session=session,
        entity_type=ENTITY_INGREDIENT,
        entity_id=7,
        action="updated",
        summary="Updated Kg per unit",
        changes=diff_fields({"kg_per_unit": 25.0}, {"kg_per_unit": 30.0}, LABELS),
    )
    # A different entity must not leak into entity 7's history.
    record_change(db, session=session, entity_type=ENTITY_MIX, entity_id=7, action="created", summary="Created mix")
    db.commit()

    events = list_changes(db, tenant_id=TENANT, entity_type=ENTITY_INGREDIENT, entity_id=7)
    assert [event.action for event in events] == ["updated", "created"]
    assert events[0].actor_name == "Lara"
    assert events[0].actor_role == "admin"
    assert events[0].changes[0]["label"] == "Kg per unit"


def test_changes_are_tenant_scoped():
    db = _session()
    record_change(
        db,
        session=AuthSession(role="internal", email="x@y.test", name="X", tenant_id="other-tenant"),
        entity_type=ENTITY_MIX,
        entity_id=1,
        action="created",
        summary="Created mix",
    )
    db.commit()

    assert list_changes(db, tenant_id=TENANT, entity_type=ENTITY_MIX, entity_id=1) == []
