from datetime import date

import pytest

from ovrapp import create_app
from ovrapp.extensions import db
from ovrapp.models import Branch, Department, Incident, Role, User
from ovrapp.policy import risk_level
from ovrapp.services import seed_reference_data


@pytest.fixture()
def app():
    app = create_app(
        {
            "TESTING": True,
            "WTF_CSRF_ENABLED": False,
            "SQLALCHEMY_DATABASE_URI": "sqlite://",
            "SESSION_COOKIE_SECURE": False,
            "MAIL_ENABLED": False,
        }
    )
    with app.app_context():
        db.create_all()
        admin = seed_reference_data("admin", "admin@example.com", "AdminPassword!2026")
        admin.must_change_password = False
        branch = db.session.scalar(db.select(Branch).where(Branch.code == "MAIN"))
        medical = db.session.scalar(db.select(Department).where(Department.branch_id == branch.id, Department.code == "MED"))
        qps_department = db.session.scalar(db.select(Department).where(Department.branch_id == branch.id, Department.code == "QPS"))
        roles = {role.code: role for role in db.session.scalars(db.select(Role)).all()}
        users = [
            User(username="reporter", email="reporter@example.com", full_name="Rina Reporter", employee_id="E-100", position="Nurse", role=roles["reporter"], branch=branch, department=medical, must_change_password=False),
            User(username="manager", email="manager@example.com", full_name="Mona Manager", employee_id="E-200", position="Department Manager", role=roles["department_manager"], branch=branch, department=medical, must_change_password=False),
            User(username="qps", email="qps@example.com", full_name="QPS Coordinator", employee_id="E-300", position="QPS Coordinator", role=roles["qps"], branch=branch, department=qps_department, must_change_password=False),
        ]
        for user in users:
            user.set_password("TestingPassword!2026")
            db.session.add(user)
        db.session.commit()
        yield app
        db.session.remove()
        db.drop_all()


@pytest.fixture()
def client(app):
    return app.test_client()


def login(client, username, password="TestingPassword!2026"):
    return client.post("/login", data={"username": username, "password": password}, follow_redirects=True)


def logout(client):
    return client.post("/logout", follow_redirects=True)


def create_incident(client, anonymous=False):
    with client.application.app_context():
        branch = db.session.scalar(db.select(Branch).where(Branch.code == "MAIN"))
        medical = db.session.scalar(db.select(Department).where(Department.code == "MED", Department.branch_id == branch.id))
        branch_id, department_id = branch.id, medical.id
    response = client.post(
        "/incidents/new",
        data={
            "branch_id": branch_id,
            "department_id": department_id,
            "incident_date": date.today().isoformat(),
            "incident_time": "09:30",
            "location": "Treatment Room 2",
            "person_type": "Patient",
            "person_name": "Test Patient",
            "patient_mrn": "MRN-001",
            "classification_category": "Safety",
            "classification_items": ["Injury"],
            "report_type": "Incident",
            "injury_occurred": "1",
            "injury_type": "Physical",
            "harm_level": "Minor",
            "likelihood": "Possible",
            "description": "The patient slipped while moving from the chair and was assessed immediately.",
            "immediate_action": "Assisted patient, completed assessment, and notified the attending clinician.",
            "is_anonymous": "1" if anonymous else "",
            "action": "submit",
        },
        follow_redirects=True,
    )
    assert response.status_code == 200
    with client.application.app_context():
        return db.session.scalar(db.select(Incident).order_by(Incident.id.desc())).id


def test_health_and_login(client):
    assert client.get("/healthz").json == {"status": "ok"}
    response = login(client, "reporter")
    assert b"Occurrence Reporting Dashboard" in response.data


def test_policy_risk_bands_are_complete():
    assert risk_level(1) == "Low"
    assert risk_level(7) == "Moderate"
    assert risk_level(12) == "High"
    assert risk_level(13) == "Extreme"
    assert risk_level(25) == "Extreme"


def test_branch_creation(client):
    login(client, "admin", "AdminPassword!2026")
    response = client.post(
        "/admin/branches",
        data={"code": "JED-01", "name": "Al Wattan Jeddah Medical Complex", "address": "Jeddah"},
        follow_redirects=True,
    )
    assert b"Branch added" in response.data
    with client.application.app_context():
        assert db.session.scalar(db.select(Branch).where(Branch.code == "JED-01")) is not None


def test_complete_standard_workflow(client):
    login(client, "reporter")
    incident_id = create_incident(client)
    logout(client)

    login(client, "manager")
    response = client.post(
        f"/incidents/{incident_id}/manager-review",
        data={
            "supervisor_action": "Patient assessed; the area was secured and the floor condition was inspected.",
            "patient_involved_confirmed": "yes",
            "medical_record_documented": "yes",
            "contributing_factors": ["Work Environmental Factors", "Task and Technology Factors"],
            "incident_causes": "Unexpected moisture at the room entrance and an incomplete environmental round.",
            "consequence": "Moderate",
            "likelihood": "Likely",
        },
        follow_redirects=True,
    )
    assert b"Manager review completed" in response.data
    logout(client)

    login(client, "qps")
    response = client.post(
        f"/incidents/{incident_id}/qps-review",
        data={
            "qps_analysis": "The manager completed containment and identified environmental and task factors.",
            "qps_recommendation": "Maintain the new environmental round control and monitor recurrence monthly.",
            "consequence": "Moderate",
            "likelihood": "Likely",
        },
        follow_redirects=True,
    )
    assert b"ready for closure" in response.data
    response = client.post(
        f"/incidents/{incident_id}/close",
        data={
            "final_feedback": "The event was reviewed, controls were reinforced, and monitoring was assigned.",
            "closure_reason": "Appropriate and complete action was taken.",
        },
        follow_redirects=True,
    )
    assert b"Incident closed" in response.data
    with client.application.app_context():
        incident = db.session.get(Incident, incident_id)
        assert incident.status == "CLOSED"
        assert incident.risk_score == 12
        assert incident.risk_level == "High"
        assert incident.risk_registered is True
        assert len(incident.workflow_logs) == 4


def test_anonymous_identity_is_masked_from_manager_but_visible_to_qps(client):
    login(client, "reporter")
    incident_id = create_incident(client, anonymous=True)
    logout(client)

    login(client, "manager")
    response = client.get(f"/incidents/{incident_id}")
    assert b"Anonymous reporter" in response.data
    assert b"Rina Reporter" not in response.data
    logout(client)

    login(client, "qps")
    response = client.get(f"/incidents/{incident_id}")
    assert b"Rina Reporter" in response.data


def test_pdf_export_is_confidential(client):
    login(client, "reporter")
    incident_id = create_incident(client)
    response = client.get(f"/incidents/{incident_id}/pdf")
    assert response.status_code == 200
    assert response.mimetype == "application/pdf"
    assert response.data.startswith(b"%PDF")
    assert len(response.data) > 1000

