class TestAuth:
    def test_login_success(self, client, seeded_db):
        resp = client.post("/api/auth/login", json={"username": "admin", "password": "admin123"})
        assert resp.status_code == 200
        data = resp.json()
        assert "access_token" in data
        assert data["user"]["username"] == "admin"
        assert data["user"]["full_name"] == "Test Admin"
        assert len(data["user"]["permissions"]) > 0

    def test_login_wrong_password(self, client, seeded_db):
        resp = client.post("/api/auth/login", json={"username": "admin", "password": "wrong"})
        assert resp.status_code in (401, 400)

    def test_login_nonexistent_user(self, client, seeded_db):
        resp = client.post("/api/auth/login", json={"username": "nobody", "password": "pass"})
        assert resp.status_code in (401, 400)

    def test_get_me_authenticated(self, client, seeded_db, auth_headers):
        resp = client.get("/api/auth/me", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert data["username"] == "admin"
        assert "permissions" in data

    def test_get_me_no_token(self, client, seeded_db):
        resp = client.get("/api/auth/me")
        assert resp.status_code in (401, 403)

    def test_change_password(self, client, seeded_db, auth_headers):
        resp = client.post("/api/auth/change-password", json={
            "old_password": "admin123",
            "new_password": "newpass456"
        }, headers=auth_headers)
        assert resp.status_code == 200

        login_resp = client.post("/api/auth/login", json={"username": "admin", "password": "newpass456"})
        assert login_resp.status_code == 200

    def test_change_password_wrong_old(self, client, seeded_db, auth_headers):
        resp = client.post("/api/auth/change-password", json={
            "old_password": "wrongold",
            "new_password": "newpass456"
        }, headers=auth_headers)
        assert resp.status_code in (400, 401)


class TestUsers:
    def test_list_users(self, client, seeded_db, auth_headers):
        resp = client.get("/api/users", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert len(data) >= 1

    def test_create_user(self, client, seeded_db, auth_headers):
        resp = client.post("/api/users", json={
            "username": "newuser",
            "email": "new@test.com",
            "password": "pass1234",
            "full_name": "New User",
            "role_ids": [seeded_db["admin_role"].id],
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_list_roles(self, client, seeded_db, auth_headers):
        resp = client.get("/api/users/roles", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert len(data) >= 2


class TestBranches:
    def test_list_branches(self, client, seeded_db, auth_headers):
        resp = client.get("/api/branches", headers=auth_headers)
        assert resp.status_code == 200

    def test_create_branch(self, client, seeded_db, auth_headers):
        resp = client.post("/api/branches", json={
            "code": "BR-002",
            "name": "North Branch",
            "address": "123 North St",
            "is_active": True,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_get_branch(self, client, seeded_db, auth_headers):
        branch = seeded_db["branch"]
        resp = client.get(f"/api/branches/{branch.id}", headers=auth_headers)
        assert resp.status_code == 200
        assert resp.json()["name"] == "Main Branch"

    def test_update_branch(self, client, seeded_db, auth_headers):
        branch = seeded_db["branch"]
        resp = client.put(f"/api/branches/{branch.id}", json={
            "name": "Updated Branch",
        }, headers=auth_headers)
        assert resp.status_code == 200

    def test_delete_nonexistent_branch(self, client, seeded_db, auth_headers):
        resp = client.delete("/api/branches/nonexistent", headers=auth_headers)
        assert resp.status_code == 404


class TestPlants:
    def _create_category(self, client, auth_headers, name="Test Category"):
        resp = client.post("/api/plants/categories", json={"name": name}, headers=auth_headers)
        assert resp.status_code in (200, 201)
        return resp.json()

    def _create_variety(self, client, auth_headers, category_id, name="Test Variety"):
        resp = client.post("/api/plants/varieties", json={
            "name": name,
            "category_id": category_id,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        return resp.json()

    def test_create_category(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        assert cat["name"] == "Test Category"

    def test_list_categories(self, client, seeded_db, auth_headers):
        self._create_category(client, auth_headers)
        resp = client.get("/api/plants/categories", headers=auth_headers)
        assert resp.status_code == 200
        assert len(resp.json()) >= 1

    def test_update_category(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        resp = client.put(f"/api/plants/categories/{cat['id']}", json={"name": "Updated Cat"}, headers=auth_headers)
        assert resp.status_code == 200

    def test_delete_category(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        resp = client.delete(f"/api/plants/categories/{cat['id']}", headers=auth_headers)
        assert resp.status_code == 200

    def test_create_variety(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        var = self._create_variety(client, auth_headers, cat["id"])
        assert var["name"] == "Test Variety"

    def test_create_plant(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        var = self._create_variety(client, auth_headers, cat["id"])
        resp = client.post("/api/plants", json={
            "name": "Mango",
            "scientific_name": "Mangifera indica",
            "variety_id": var["id"],
            "retail_price": 500,
            "wholesale_price": 400,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        data = resp.json()
        assert data["name"] == "Mango"
        assert "PLT-" in data["code"]

    def test_list_plants(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        var = self._create_variety(client, auth_headers, cat["id"])
        client.post("/api/plants", json={"name": "Rose", "variety_id": var["id"]}, headers=auth_headers)
        resp = client.get("/api/plants", headers=auth_headers)
        assert resp.status_code == 200

    def test_search_plants(self, client, seeded_db, auth_headers):
        cat = self._create_category(client, auth_headers)
        var = self._create_variety(client, auth_headers, cat["id"])
        client.post("/api/plants", json={"name": "Jasmine", "variety_id": var["id"]}, headers=auth_headers)
        resp = client.get("/api/plants?search=Jasmine", headers=auth_headers)
        assert resp.status_code == 200


class TestProduction:
    def _setup_plant(self, client, auth_headers):
        cat_resp = client.post("/api/plants/categories", json={"name": "Flowers"}, headers=auth_headers)
        cat = cat_resp.json()
        var_resp = client.post("/api/plants/varieties", json={"name": "Rose", "category_id": cat["id"]}, headers=auth_headers)
        var = var_resp.json()
        plant_resp = client.post("/api/plants", json={"name": "Rose Plant", "variety_id": var["id"]}, headers=auth_headers)
        return plant_resp.json()

    def test_create_seed_lot(self, client, seeded_db, auth_headers):
        plant = self._setup_plant(client, auth_headers)
        resp = client.post("/api/production/seed-lots", json={
            "plant_id": plant["id"],
            "lot_number": "SL-001",
            "quantity": 1000,
            "purchase_date": "2026-07-01",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_create_batch(self, client, seeded_db, auth_headers):
        plant = self._setup_plant(client, auth_headers)
        resp = client.post("/api/production/batches", json={
            "plant_id": plant["id"],
            "sowing_date": "2026-07-15",
            "sown_quantity": 200,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        data = resp.json()
        assert "BAT-" in data["batch_number"]
        assert data["sown_quantity"] == 200
        return data

    def test_list_batches(self, client, seeded_db, auth_headers):
        self.test_create_batch(client, seeded_db, auth_headers)
        resp = client.get("/api/production/batches", headers=auth_headers)
        assert resp.status_code == 200
        assert len(resp.json()) >= 1

    def test_update_batch_status(self, client, seeded_db, auth_headers):
        batch = self.test_create_batch(client, seeded_db, auth_headers)
        resp = client.put(f"/api/production/batches/{batch['id']}", json={"status": "germination"}, headers=auth_headers)
        assert resp.status_code == 200

    def test_create_germination_record(self, client, seeded_db, auth_headers):
        batch = self.test_create_batch(client, seeded_db, auth_headers)
        resp = client.post("/api/production/germination", json={
            "batch_id": batch["id"],
            "date": "2026-07-20",
            "germinated_quantity": 150,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        data = resp.json()
        assert data["success_rate"] == 75.0

    def test_create_transplant_record(self, client, seeded_db, auth_headers):
        batch = self.test_create_batch(client, seeded_db, auth_headers)
        resp = client.post("/api/production/transplants", json={
            "batch_id": batch["id"],
            "date": "2026-08-01",
            "from_container": "Tray A",
            "to_container": "Tray B",
            "quantity": 100,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)


class TestInventory:
    def test_create_item(self, client, seeded_db, auth_headers):
        resp = client.post("/api/inventory", json={
            "name": "Fertilizer",
            "category": "chemicals",
            "quantity": 50,
            "unit": "kg",
            "unit_cost": 25.0,
            "reorder_level": 10,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        data = resp.json()
        assert "INV-" in data["code"]

    def test_list_inventory(self, client, seeded_db, auth_headers):
        client.post("/api/inventory", json={
            "name": "Pesticide", "category": "chemicals", "quantity": 20, "unit": "L",
            "unit_cost": 50.0, "reorder_level": 5,
        }, headers=auth_headers)
        resp = client.get("/api/inventory", headers=auth_headers)
        assert resp.status_code == 200

    def test_create_transaction(self, client, seeded_db, auth_headers):
        item_resp = client.post("/api/inventory", json={
            "name": "Soil", "category": "substrate", "quantity": 100, "unit": "kg",
            "unit_cost": 5.0, "reorder_level": 20,
        }, headers=auth_headers)
        item = item_resp.json()
        resp = client.post("/api/inventory/transactions", json={
            "item_id": item["id"],
            "type": "out",
            "quantity": 10,
            "notes": "Used in production",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_update_item(self, client, seeded_db, auth_headers):
        item_resp = client.post("/api/inventory", json={
            "name": "Mulch", "category": "organic", "quantity": 30, "unit": "bags",
            "unit_cost": 15.0, "reorder_level": 5,
        }, headers=auth_headers)
        item = item_resp.json()
        resp = client.put(f"/api/inventory/{item['id']}", json={"name": "Premium Mulch"}, headers=auth_headers)
        assert resp.status_code == 200


class TestSuppliers:
    def test_create_supplier(self, client, seeded_db, auth_headers):
        resp = client.post("/api/suppliers", json={
            "name": "Green Supplies Co.",
            "contact_person": "John",
            "phone": "+8801712345678",
            "email": "john@green.com",
            "address": "Dhaka",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        assert "SUP-" in resp.json()["code"]

    def test_list_suppliers(self, client, seeded_db, auth_headers):
        client.post("/api/suppliers", json={"name": "Seed World", "phone": "+8801812345678"}, headers=auth_headers)
        resp = client.get("/api/suppliers", headers=auth_headers)
        assert resp.status_code == 200

    def test_update_supplier(self, client, seeded_db, auth_headers):
        s = client.post("/api/suppliers", json={"name": "Old Name"}, headers=auth_headers).json()
        resp = client.put(f"/api/suppliers/{s['id']}", json={"name": "New Name"}, headers=auth_headers)
        assert resp.status_code == 200


class TestCustomers:
    def test_create_customer(self, client, seeded_db, auth_headers):
        resp = client.post("/api/customers", json={
            "name": "Rahim Enterprise",
            "customer_type": "retail",
            "phone": "+8801912345678",
            "email": "rahim@test.com",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        assert "CUS-" in resp.json()["code"]

    def test_list_customers(self, client, seeded_db, auth_headers):
        client.post("/api/customers", json={"name": "Karim Traders", "customer_type": "wholesale"}, headers=auth_headers)
        resp = client.get("/api/customers", headers=auth_headers)
        assert resp.status_code == 200

    def test_filter_by_type(self, client, seeded_db, auth_headers):
        client.post("/api/customers", json={"name": "Retail Shop", "customer_type": "retail"}, headers=auth_headers)
        client.post("/api/customers", json={"name": "Wholesale Hub", "customer_type": "wholesale"}, headers=auth_headers)
        resp = client.get("/api/customers?customer_type=retail", headers=auth_headers)
        assert resp.status_code == 200


class TestEmployees:
    def _create_employee(self, client, auth_headers):
        resp = client.post("/api/employees", json={
            "name": "Karim Worker",
            "department": "production",
            "role": "Nursery Worker",
            "phone": "+8801612345678",
            "joining_date": "2026-01-01",
            "salary": 15000,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        return resp.json()

    def test_create_employee(self, client, seeded_db, auth_headers):
        emp = self._create_employee(client, auth_headers)
        assert "EMP-" in emp["code"]

    def test_record_attendance(self, client, seeded_db, auth_headers):
        emp = self._create_employee(client, auth_headers)
        resp = client.post("/api/employees/attendance", json={
            "employee_id": emp["id"],
            "date": "2026-07-26",
            "status": "present",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_create_leave(self, client, seeded_db, auth_headers):
        emp = self._create_employee(client, auth_headers)
        resp = client.post("/api/employees/leaves", json={
            "employee_id": emp["id"],
            "leave_type": "sick",
            "start_date": "2026-08-01",
            "end_date": "2026-08-03",
            "reason": "Personal",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)


class TestFinance:
    def test_create_account(self, client, seeded_db, auth_headers):
        resp = client.post("/api/finance/accounts", json={
            "name": "Main Cash",
            "type": "cash",
            "balance": 100000,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_create_expense(self, client, seeded_db, auth_headers):
        resp = client.post("/api/finance/expenses", json={
            "description": "Fertilizer purchase",
            "amount": 5000,
            "category": "supplies",
            "date": "2026-07-26",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        assert "EXP-" in resp.json()["expense_number"]

    def test_create_income(self, client, seeded_db, auth_headers):
        resp = client.post("/api/finance/income", json={
            "description": "Plant sale revenue",
            "amount": 25000,
            "category": "sales",
            "date": "2026-07-26",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        assert "INC-" in resp.json()["income_number"]

    def test_list_expenses(self, client, seeded_db, auth_headers):
        client.post("/api/finance/expenses", json={
            "description": "Water bill", "amount": 2000, "category": "utilities", "date": "2026-07-26",
        }, headers=auth_headers)
        resp = client.get("/api/finance/expenses", headers=auth_headers)
        assert resp.status_code == 200


class TestTreatments:
    def _setup_batch(self, client, auth_headers):
        cat = client.post("/api/plants/categories", json={"name": "Trees"}, headers=auth_headers).json()
        var = client.post("/api/plants/varieties", json={"name": "Mango", "category_id": cat["id"]}, headers=auth_headers).json()
        plant = client.post("/api/plants", json={"name": "Mango Plant", "variety_id": var["id"]}, headers=auth_headers).json()
        batch = client.post("/api/production/batches", json={
            "plant_id": plant["id"], "sowing_date": "2026-07-01", "sown_quantity": 100,
        }, headers=auth_headers).json()
        return batch

    def test_create_treatment(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.post("/api/treatments", json={
            "batch_id": batch["id"],
            "treatment_type": "irrigation",
            "treatment_date": "2026-07-26",
            "status": "completed",
            "cost": 500,
            "notes": "Regular irrigation",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)
        assert "TRT-" in resp.json()["treatment_number"]

    def test_create_health_record(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.post("/api/treatments/health", json={
            "batch_id": batch["id"],
            "record_date": "2026-07-26",
            "plant_height_cm": 15.5,
            "leaf_count": 8,
            "health_score": 85,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_create_disease_record(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.post("/api/treatments/disease-pest", json={
            "batch_id": batch["id"],
            "record_date": "2026-07-26",
            "name": "Aphids",
            "type": "pest",
            "severity": "low",
            "status": "active",
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_create_schedule(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.post("/api/treatments/schedules", json={
            "batch_id": batch["id"],
            "treatment_type": "fertilization",
            "frequency_days": 7,
            "next_due_date": "2026-08-01",
            "is_active": True,
        }, headers=auth_headers)
        assert resp.status_code in (200, 201)

    def test_treatment_analytics(self, client, seeded_db, auth_headers):
        resp = client.get("/api/treatments/analytics/summary", headers=auth_headers)
        assert resp.status_code == 200


class TestScanQR:
    def _setup_batch(self, client, auth_headers):
        cat = client.post("/api/plants/categories", json={"name": "Fruit Trees"}, headers=auth_headers).json()
        var = client.post("/api/plants/varieties", json={"name": "Jackfruit", "category_id": cat["id"]}, headers=auth_headers).json()
        plant = client.post("/api/plants", json={"name": "Jackfruit Plant", "variety_id": var["id"]}, headers=auth_headers).json()
        batch = client.post("/api/production/batches", json={
            "plant_id": plant["id"], "sowing_date": "2026-07-01", "sown_quantity": 50,
        }, headers=auth_headers).json()
        return batch

    def test_scan_batch(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.get(f"/api/scan/{batch['batch_number']}", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert data["batch_number"] == batch["batch_number"]
        assert data["plant_name"] == "Jackfruit Plant"

    def test_scan_nonexistent(self, client, seeded_db, auth_headers):
        resp = client.get("/api/scan/NONEXISTENT", headers=auth_headers)
        assert resp.status_code == 404

    def test_qr_generation(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.get(f"/api/qr/{batch['id']}", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert "qr_base64" in data
        assert "scan_url" in data
        assert "http://" in data["scan_url"]
        assert "/s/" in data["scan_url"]

    def test_public_scan_page(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.get(f"/s/{batch['batch_number']}")
        assert resp.status_code == 200
        assert batch["batch_number"] in resp.text

    def test_public_scan_page_not_found(self, client, seeded_db):
        resp = client.get("/s/NONEXISTENT")
        assert resp.status_code == 404

    def test_qr_print_data(self, client, seeded_db, auth_headers):
        batch = self._setup_batch(client, auth_headers)
        resp = client.get(f"/api/qr/batch/{batch['id']}/print", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert "qr_base64" in data
        assert data["batch_number"] == batch["batch_number"]


class TestDashboard:
    def test_dashboard(self, client, seeded_db, auth_headers):
        resp = client.get("/api/dashboard", headers=auth_headers)
        assert resp.status_code == 200
        data = resp.json()
        assert "stats" in data
        assert "total_plants" in data["stats"]


class TestReports:
    def test_inventory_report(self, client, seeded_db, auth_headers):
        resp = client.get("/api/reports/inventory", headers=auth_headers)
        assert resp.status_code == 200

    def test_production_report(self, client, seeded_db, auth_headers):
        resp = client.get("/api/reports/production", headers=auth_headers)
        assert resp.status_code == 200

    def test_sales_report(self, client, seeded_db, auth_headers):
        resp = client.get("/api/reports/sales", headers=auth_headers)
        assert resp.status_code == 200

    def test_profit_loss_report(self, client, seeded_db, auth_headers):
        resp = client.get("/api/reports/profit-loss", headers=auth_headers)
        assert resp.status_code == 200


class TestAlerts:
    def test_list_alerts(self, client, seeded_db, auth_headers):
        resp = client.get("/api/alerts", headers=auth_headers)
        assert resp.status_code == 200

    def test_unread_count(self, client, seeded_db, auth_headers):
        resp = client.get("/api/alerts/unread-count", headers=auth_headers)
        assert resp.status_code == 200
