import uuid

import pytest
from sqlalchemy import select

from app.core.security import hash_password
from app.db.session import SessionLocal
from app.models.audit import AuditLog
from app.models.inventory import BranchInventory
from app.models.membership import Membership
from app.models.user import User

from test_products_inventory import another_business, headers, product, workspace


pytest_plugins = ("test_workspace",)


def test_product_patch_preserves_stock_and_creates_audit(client, verified_user):
    data = workspace(client, verified_user, "Product edit")
    business, branch = data["business"]["id"], data["accessible_branches"][0]["id"]
    created = product(client, verified_user, business, "Before", description="Original", purchase_price="2", selling_price="5", low_stock_alert="3").json()
    assert client.post(f"/api/businesses/{business}/branches/{branch}/stock-adjustments", json={"product_id": created["id"], "quantity_changed": "9", "reason": "RESTOCK"}, headers=headers(verified_user)).status_code == 201
    response = client.patch(f"/api/businesses/{business}/products/{created['id']}", json={"name": "After", "selling_price": "7"}, headers=headers(verified_user))
    assert response.status_code == 200 and response.json()["name"] == "After" and response.json()["description"] == "Original" and response.json()["selling_price"] == 7
    db = SessionLocal()
    try:
        stock = db.scalar(select(BranchInventory.quantity).where(BranchInventory.product_id == uuid.UUID(created["id"]), BranchInventory.branch_id == uuid.UUID(branch)))
        audit = db.scalar(select(AuditLog).where(AuditLog.business_id == uuid.UUID(business), AuditLog.action == "PRODUCT_UPDATED", AuditLog.entity_id == uuid.UUID(created["id"])))
        assert stock == 9 and audit.actor_user_id == verified_user.id and audit.details["changed_fields"] == ["name", "selling_price"]
    finally: db.close()


def test_product_patch_status_permissions_isolation_and_filtering(client, verified_user):
    first = workspace(client, verified_user, "Product status")
    business = first["business"]["id"]
    created = product(client, verified_user, business, "Status product").json()
    second = another_business(client, verified_user, "Other product business")["business"]["id"]
    endpoint = f"/api/businesses/{business}/products/{created['id']}"
    assert client.patch(endpoint, json={"product_type": "VARIATION"}, headers=headers(verified_user)).status_code == 422
    assert client.patch(f"/api/businesses/{second}/products/{created['id']}", json={"name": "No"}, headers=headers(verified_user)).status_code == 404
    disabled = client.patch(f"{endpoint}/status", json={"is_active": False}, headers=headers(verified_user))
    assert disabled.status_code == 200 and disabled.json()["is_active"] is False
    assert [item["id"] for item in client.get(f"/api/businesses/{business}/products?status_filter=inactive", headers=headers(verified_user)).json()] == [created["id"]]
    assert client.get(f"/api/businesses/{business}/products/{created['id']}", headers=headers(verified_user)).status_code == 200
    assert client.patch(f"{endpoint}/status", json={"is_active": True}, headers=headers(verified_user)).status_code == 200
    db = SessionLocal(); outsider = User(full_name="Cashier", email=f"product-cashier-{uuid.uuid4().hex}@x.test", password_hash=hash_password("Password123!"), is_email_verified=True)
    try:
        db.add(outsider); db.flush(); db.add(Membership(business_id=uuid.UUID(business), user_id=outsider.id, role="CASHIER", all_branches=True)); db.commit()
        assert client.patch(endpoint, json={"name": "Denied"}, headers=headers(outsider)).status_code == 403
        status_audit = db.scalar(select(AuditLog).where(AuditLog.business_id == uuid.UUID(business), AuditLog.action == "PRODUCT_STATUS_CHANGED", AuditLog.entity_id == uuid.UUID(created["id"])))
        assert status_audit is not None and status_audit.actor_user_id == verified_user.id
    finally:
        db.query(Membership).filter(Membership.user_id == outsider.id).delete(); db.query(User).filter(User.id == outsider.id).delete(); db.commit(); db.close()
