import os
import sys
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from app.database import Base, get_db
from app.main import app
from app.services.auth import hash_password, create_access_token
from app.models.user import User, Role, Permission, UserRole, RolePermission
from app.models.branch import Branch

TEST_DATABASE_URL = "sqlite:///./test_nursery_ops.db"
engine = create_engine(TEST_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)


def override_get_db():
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


app.dependency_overrides[get_db] = override_get_db


@pytest.fixture(scope="function", autouse=True)
def setup_database():
    Base.metadata.create_all(bind=engine)
    yield
    Base.metadata.drop_all(bind=engine)


@pytest.fixture(scope="function")
def db():
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


@pytest.fixture(scope="function")
def client():
    return TestClient(app)


@pytest.fixture(scope="function")
def seeded_db(db):
    """Seed the test database with roles, permissions, admin user, and branch."""
    modules = ["plants", "production", "inventory", "sales", "purchases",
               "employees", "finance", "treatments", "reports", "users", "branches", "accounting"]
    actions = ["view", "create", "edit", "delete"]
    perms = {}
    for m in modules:
        for a in actions:
            p = Permission(module=m, action=a)
            db.add(p)
            db.flush()
            perms[(m, a)] = p

    admin_role = Role(name="super_admin", description="Full system access")
    db.add(admin_role)
    db.flush()
    for p in perms.values():
        db.add(RolePermission(role_id=admin_role.id, permission_id=p.id))

    manager_role = Role(name="manager", description="Branch manager")
    db.add(manager_role)
    db.flush()
    for m in modules:
        for a in actions:
            db.add(RolePermission(role_id=manager_role.id, permission_id=perms[(m, a)].id))

    branch = Branch(code="BR-001", name="Main Branch", address="Head Office", is_active=True)
    db.add(branch)
    db.flush()

    from app.services.accounting import seed_chart_of_accounts
    seed_chart_of_accounts(db)

    admin = User(
        username="admin",
        email="admin@test.com",
        password_hash=hash_password("admin123"),
        full_name="Test Admin",
        is_active=True,
        branch_id=branch.id,
    )
    admin.roles = [admin_role]
    db.add(admin)
    db.commit()
    db.refresh(admin)

    return {"admin": admin, "admin_role": admin_role, "manager_role": manager_role, "branch": branch, "perms": perms}


@pytest.fixture(scope="function")
def auth_headers(seeded_db):
    """Return authorization headers for the admin user."""
    token = create_access_token({"sub": seeded_db["admin"].id})
    return {"Authorization": f"Bearer {token}"}


@pytest.fixture(scope="function")
def manager_headers(seeded_db):
    """Return authorization headers for a manager user (no super_admin)."""
    db = TestingSessionLocal()
    try:
        manager = User(
            username="manager",
            email="manager@test.com",
            password_hash=hash_password("manager123"),
            full_name="Test Manager",
            is_active=True,
            branch_id=seeded_db["branch"].id,
        )
        manager.roles = [seeded_db["manager_role"]]
        db.add(manager)
        db.commit()
        db.refresh(manager)
        token = create_access_token({"sub": manager.id})
        return {"Authorization": f"Bearer {token}"}
    finally:
        db.close()
