"""Covers app/crud/formula.py (unit-level safety/correctness) and the
Masters record endpoints' formula wiring (integration-level): a client must
never be able to set a formula field's value directly, and the computed
value must be correct and recomputed on every write."""

import pytest

from app.crud.formula import FormulaError, compute_formula_fields, evaluate_formula


def test_evaluate_formula_basic_arithmetic():
    assert evaluate_formula("{quantity} * {unit_price}", {"quantity": 7, "unit_price": 4.5}) == 31.5


def test_evaluate_formula_with_whitelisted_function():
    assert evaluate_formula("round({total}, 1)", {"total": 3.14159}) == 3.1


def test_evaluate_formula_missing_field_treated_as_none_raises_formula_error():
    with pytest.raises(FormulaError):
        evaluate_formula("{quantity} * {unit_price}", {"quantity": 7})


def test_evaluate_formula_rejects_import():
    with pytest.raises(FormulaError):
        evaluate_formula("__import__('os').system('echo pwned')", {})


def test_evaluate_formula_rejects_attribute_access():
    with pytest.raises(FormulaError):
        evaluate_formula("{x}.__class__", {"x": 1})


def test_compute_formula_fields_swallows_errors_as_none():
    field_defs = [{"name": "total", "type": "formula", "formula_expression": "{a} / {b}"}]
    assert compute_formula_fields(field_defs, {"a": 10, "b": 0}) == {"total": None}


def test_compute_formula_fields_ignores_non_formula_fields():
    field_defs = [{"name": "title", "type": "text"}, {"name": "total", "type": "formula", "formula_expression": "{a}+{b}"}]
    assert compute_formula_fields(field_defs, {"a": 2, "b": 3}) == {"total": 5}


async def test_master_record_computes_formula_on_create(client, auth_headers):
    master_resp = await client.post(
        "/masters",
        headers=auth_headers,
        json={
            "name": "Formula Test",
            "field_schema": [
                {"name": "quantity", "type": "number"},
                {"name": "unit_price", "type": "number"},
                {"name": "total", "type": "formula", "formula_expression": "{quantity} * {unit_price}"},
            ],
        },
    )
    assert master_resp.status_code == 201
    master_id = master_resp.json()["id"]

    record_resp = await client.post(
        f"/masters/{master_id}/records",
        headers=auth_headers,
        json={"field_values": {"quantity": 3, "unit_price": 5}},
    )
    assert record_resp.status_code == 201
    assert record_resp.json()["field_values"]["total"] == 15


async def test_master_record_rejects_client_supplied_formula_value(client, auth_headers):
    master_resp = await client.post(
        "/masters",
        headers=auth_headers,
        json={
            "name": "Formula Override Test",
            "field_schema": [
                {"name": "quantity", "type": "number"},
                {"name": "unit_price", "type": "number"},
                {"name": "total", "type": "formula", "formula_expression": "{quantity} * {unit_price}"},
            ],
        },
    )
    master_id = master_resp.json()["id"]

    record_resp = await client.post(
        f"/masters/{master_id}/records",
        headers=auth_headers,
        json={"field_values": {"quantity": 3, "unit_price": 5, "total": 999}},
    )
    assert record_resp.status_code == 422
    assert "computed" in record_resp.json()["detail"][0]


async def test_master_record_recomputes_formula_on_update(client, auth_headers):
    master_resp = await client.post(
        "/masters",
        headers=auth_headers,
        json={
            "name": "Formula Update Test",
            "field_schema": [
                {"name": "quantity", "type": "number"},
                {"name": "unit_price", "type": "number"},
                {"name": "total", "type": "formula", "formula_expression": "{quantity} * {unit_price}"},
            ],
        },
    )
    master_id = master_resp.json()["id"]
    record_resp = await client.post(
        f"/masters/{master_id}/records", headers=auth_headers, json={"field_values": {"quantity": 2, "unit_price": 10}}
    )
    record_id = record_resp.json()["id"]
    assert record_resp.json()["field_values"]["total"] == 20

    update_resp = await client.patch(
        f"/masters/{master_id}/records/{record_id}",
        headers=auth_headers,
        json={"field_values": {"quantity": 5, "unit_price": 10}},
    )
    assert update_resp.status_code == 200
    assert update_resp.json()["field_values"]["total"] == 50
