from datetime import date, timedelta

from app.models.agency import Agency
from app.models.customer import Customer
from app.models.enums import PolicyStatus


def _policy_payload(customer_id: int, policy_number: str) -> dict:
    return {
        "customer_id": customer_id,
        "policy_number": policy_number,
        "policy_end_date": (date.today() + timedelta(days=365)).isoformat(),
    }


def test_create_policy_requires_policy_number(client, auth_headers, seed_data):
    customer_id = seed_data["customer"].id
    response = client.post(
        "/api/v1/policies",
        json={
            "customer_id": customer_id,
            "policy_end_date": "2027-12-31",
        },
        headers=auth_headers,
    )
    assert response.status_code == 422
    assert any(d.get("field") == "policy_number" for d in response.json().get("details", []))


def test_create_policy_rejects_duplicate_policy_number(client, auth_headers, seed_data):
    customer_id = seed_data["customer"].id
    existing_number = seed_data["policy"].policy_number

    response = client.post(
        "/api/v1/policies",
        json=_policy_payload(customer_id, existing_number),
        headers=auth_headers,
    )
    assert response.status_code == 422
    body = response.json()
    assert body["code"] == "VALIDATION_ERROR"
    assert any(d.get("field") == "policy_number" for d in body.get("details", []))


def test_create_policy_rejects_duplicate_case_insensitive(client, auth_headers, seed_data):
    customer_id = seed_data["customer"].id
    existing_number = seed_data["policy"].policy_number.lower()

    response = client.post(
        "/api/v1/policies",
        json=_policy_payload(customer_id, existing_number),
        headers=auth_headers,
    )
    assert response.status_code == 422


def test_update_policy_rejects_duplicate_policy_number(client, auth_headers, db, seed_data):
    agency = seed_data["agency"]
    customer = Customer(agency_id=agency.id, name="Other Customer", mobile="8888800001")
    db.add(customer)
    db.commit()

    second = client.post(
        "/api/v1/policies",
        json=_policy_payload(customer.id, "POL-UNIQUE-002"),
        headers=auth_headers,
    )
    assert second.status_code == 200

    response = client.put(
        f"/api/v1/policies/{second.json()['id']}",
        json={"policy_number": seed_data["policy"].policy_number},
        headers=auth_headers,
    )
    assert response.status_code == 422


def test_update_same_policy_keeps_policy_number(client, auth_headers, seed_data):
    policy_id = seed_data["policy"].id
    policy_number = seed_data["policy"].policy_number

    response = client.put(
        f"/api/v1/policies/{policy_id}",
        json={"policy_number": policy_number, "notes": "unchanged number"},
        headers=auth_headers,
    )
    assert response.status_code == 200
    assert response.json()["policy_number"] == policy_number


def test_renewed_policy_does_not_block_same_policy_number(client, auth_headers, db, seed_data):
    policy = seed_data["policy"]
    policy.status = PolicyStatus.RENEWED
    db.commit()

    response = client.post(
        "/api/v1/policies",
        json=_policy_payload(seed_data["customer"].id, policy.policy_number),
        headers=auth_headers,
    )
    assert response.status_code == 200


def test_same_policy_number_allowed_in_different_agency(client, auth_headers, db, seed_data):
    other_agency = Agency(name="Other Agency", phone="8888888888", email="other@agency.local")
    db.add(other_agency)
    db.flush()
    other_customer = Customer(agency_id=other_agency.id, name="Cross Agency", mobile="7777700001")
    db.add(other_customer)
    db.commit()

    # Seed policy exists in test agency; another agency's user would need their own auth.
    # Verify repository scope: duplicate check is per agency only via direct create in same agency test above.
    from app.repositories.policy_repository import PolicyRepository

    repo = PolicyRepository(db)
    assert repo.find_by_policy_number(seed_data["agency"].id, seed_data["policy"].policy_number) is not None
    assert repo.find_by_policy_number(other_agency.id, seed_data["policy"].policy_number) is None
