import re
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 valid_ean13(value):
    return bool(re.fullmatch(r"\d{13}", value)) and sum(int(digit)*(1 if index % 2 == 0 else 3) for index,digit in enumerate(value[:-1])) % 10 + int(value[-1]) in {0, 10}


def test_generate_barcode_stores_unique_ean_and_audits_without_stock_change(client, verified_user):
    data=workspace(client,verified_user,"Barcode store"); business,branch=data["business"]["id"],data["accessible_branches"][0]["id"]
    first=product(client,verified_user,business,"First").json(); second=product(client,verified_user,business,"Second").json()
    assert client.post(f"/api/businesses/{business}/branches/{branch}/stock-adjustments",json={"product_id":first["id"],"quantity_changed":"4","reason":"RESTOCK"},headers=headers(verified_user)).status_code==201
    generated=client.post(f"/api/businesses/{business}/products/{first['id']}/barcode/generate",headers=headers(verified_user)); assert generated.status_code==200
    barcode=generated.json()["barcode"]; assert valid_ean13(barcode) and barcode.startswith("20")
    second_code=client.post(f"/api/businesses/{business}/products/{second['id']}/barcode/generate",headers=headers(verified_user)).json()["barcode"]; assert second_code!=barcode
    assert client.get(f"/api/businesses/{business}/products?barcode={barcode}",headers=headers(verified_user)).json()[0]["id"]==first["id"]
    assert client.post(f"/api/businesses/{business}/products/{first['id']}/barcode/generate",headers=headers(verified_user)).status_code==422
    db=SessionLocal()
    try:
        assert db.scalar(select(BranchInventory.quantity).where(BranchInventory.product_id==uuid.UUID(first["id"])))==4
        audit=db.scalar(select(AuditLog).where(AuditLog.action=="PRODUCT_BARCODE_GENERATED",AuditLog.entity_id==uuid.UUID(first["id"])))
        assert audit.business_id==uuid.UUID(business) and audit.actor_user_id==verified_user.id and audit.details["barcode"]==barcode
    finally: db.close()


def test_manual_and_creation_duplicates_are_scoped_and_generation_is_protected(client, verified_user):
    data=workspace(client,verified_user,"Barcode safety");business=data["business"]["id"]
    first=product(client,verified_user,business,"First",barcode="  manufacturer-123 ").json(); second=product(client,verified_user,business,"Second").json()
    assert first["barcode"]=="manufacturer-123"
    assert product(client,verified_user,business,"Duplicate",barcode="manufacturer-123").status_code==409
    assert client.patch(f"/api/businesses/{business}/products/{second['id']}",json={"barcode":"manufacturer-123"},headers=headers(verified_user)).status_code==409
    other=another_business(client,verified_user,"Other barcode")["business"]["id"]
    assert product(client,verified_user,other,"Allowed",barcode="manufacturer-123").status_code==201
    db=SessionLocal();cashier=User(full_name="Cashier",email=f"barcode-{uuid.uuid4().hex}@x.test",password_hash=hash_password("Password123!"),is_email_verified=True)
    try:
        db.add(cashier);db.flush();db.add(Membership(business_id=uuid.UUID(business),user_id=cashier.id,role="CASHIER",all_branches=True));db.commit()
        assert client.post(f"/api/businesses/{business}/products/{second['id']}/barcode/generate",headers=headers(cashier)).status_code==403
        assert client.post(f"/api/businesses/{business}/products/{uuid.uuid4()}/barcode/generate",headers=headers(verified_user)).status_code==404
    finally:
        db.query(Membership).filter(Membership.user_id==cashier.id).delete();db.query(User).filter(User.id==cashier.id).delete();db.commit();db.close()
