import unittest
from fastapi.testclient import TestClient

from app.main import create_app
from app.modules.auth.presentation.auth import get_current_user


class TestViewerSecurityRestrictions(unittest.TestCase):
    """
    Test suite verifying that users with 'viewer' role are strictly blocked (HTTP 403)
    from accessing internal confidential modules and mutating operations:
    - Debt Ledger (TK 131, TK 331, TK 211, TK 214)
    - Bank Statements & Balances (4 Bank Accounts, 943 Transactions)
    - State Treasury Dossiers (Kho Bạc NĐ 254/2025/NĐ-CP)
    - HR Timesheets & Payroll
    - 4 Pillars Financial Reconciliations & Quality Audits
    - Inventory Truth & Material Dispatches
    - CAD Drawing Takeoff Mutations & AI Training
    """

    def setUp(self):
        self.app = create_app()
        self.client = TestClient(self.app)

    def tearDown(self):
        self.app.dependency_overrides = {}

    def _set_user(self, role: str, email: str = "test@dscons.vn"):
        self.app.dependency_overrides[get_current_user] = lambda: {
            "id": f"test-user-{role}-id",
            "email": email,
            "full_name": f"Test {role.title()}",
            "role": role,
            "is_active": True,
        }

    # 1. Debt Ledger Tests
    def test_viewer_blocked_from_debt_ledger(self):
        self._set_user("viewer")
        response = self.client.get("/v1/erp/finance/debt-ledger")
        self.assertEqual(response.status_code, 403)

    def test_accountant_allowed_debt_ledger(self):
        self._set_user("accountant")
        response = self.client.get("/v1/erp/finance/debt-ledger")
        self.assertNotEqual(response.status_code, 403)

    # 2. Bank Statements & Balances Tests
    def test_viewer_blocked_from_bank_transactions(self):
        self._set_user("viewer")
        response = self.client.get("/v1/erp/finance/bank-transactions")
        self.assertEqual(response.status_code, 403)

    def test_viewer_blocked_from_bank_summary(self):
        self._set_user("viewer")
        response = self.client.get("/v1/erp/finance/bank-summary")
        self.assertEqual(response.status_code, 403)

    def test_accountant_allowed_bank_summary(self):
        self._set_user("accountant")
        response = self.client.get("/v1/erp/finance/bank-summary")
        self.assertNotEqual(response.status_code, 403)

    # 3. HR Timesheets Tests
    def test_viewer_blocked_from_hr_timesheets(self):
        self._set_user("viewer")
        response = self.client.get("/v1/erp/hr/timesheets")
        self.assertEqual(response.status_code, 403)

    def test_director_allowed_hr_timesheets(self):
        self._set_user("director")
        response = self.client.get("/v1/erp/hr/timesheets")
        self.assertNotEqual(response.status_code, 403)

    # 4. State Treasury Dossier Tests
    def test_viewer_blocked_from_treasury_dossier(self):
        self._set_user("viewer")
        response = self.client.get("/v1/erp/dossier/treasury/data")
        self.assertEqual(response.status_code, 403)

    def test_qs_allowed_treasury_dossier(self):
        self._set_user("qs")
        response = self.client.get("/v1/erp/dossier/treasury/data")
        self.assertNotEqual(response.status_code, 403)

    # 5. Inventory Truth & Dispatches Tests
    def test_viewer_blocked_from_inventory_truth_extract(self):
        self._set_user("viewer")
        response = self.client.post("/v1/erp/inventory-truth/extract-from-invoices")
        self.assertEqual(response.status_code, 403)

    def test_viewer_blocked_from_inventory_dispatch(self):
        self._set_user("viewer")
        response = self.client.post(
            "/v1/erp/inventory-truth/dispatch",
            json={
                "project_code": "TEST-PROJ",
                "item_name": "Thép D10",
                "quantity": 100,
            },
        )
        self.assertEqual(response.status_code, 403)

    # 6. Takeoff Mutation Tests
    def test_viewer_blocked_from_takeoff_upload(self):
        self._set_user("viewer")
        response = self.client.post(
            "/v1/takeoff/upload",
            files={"file": ("test.pdf", b"%PDF-1.4 dummy", "application/pdf")},
        )
        self.assertEqual(response.status_code, 403)

    def test_viewer_blocked_from_takeoff_batch_upload(self):
        self._set_user("viewer")
        response = self.client.post(
            "/v1/takeoff/upload-batch",
            files=[("files", ("test.pdf", b"%PDF-1.4 dummy", "application/pdf"))],
        )
        self.assertEqual(response.status_code, 403)

    # 7. Four Pillars Financial Reconciliations Tests
    def test_viewer_blocked_from_four_pillars_3way_match(self):
        self._set_user("viewer")
        response = self.client.get("/v1/pillars/epc/3-way-match/PROJ-01")
        self.assertEqual(response.status_code, 403)

    def test_viewer_blocked_from_four_pillars_equipment_rental_reconcile(self):
        self._set_user("viewer")
        response = self.client.get("/v1/pillars/equipment/rental-reconcile")
        self.assertEqual(response.status_code, 403)

    def test_viewer_blocked_from_four_pillars_sludge_transport_reconcile(self):
        self._set_user("viewer")
        response = self.client.get("/v1/pillars/logistics/sludge-transport/reconcile")
        self.assertEqual(response.status_code, 403)


if __name__ == "__main__":
    unittest.main()
