from __future__ import annotations

from datetime import datetime, timedelta, timezone
import json

from eightmem.core.governance import (
    GovernancePolicy,
    create_approval_request,
    ensure_governance_policy,
    evaluate_action,
    evaluate_notification,
    get_approval_request,
    resolve_approval_request,
    save_governance_policy,
)


def test_governance_policy_is_created_with_defaults(fake_home):
    policy = ensure_governance_policy()

    assert policy.action_policies["email_send"] == "ask_first"
    assert policy.notification_policies["email"] == "notify_if_urgent"
    assert (fake_home / "governance.json").exists()


def test_governance_action_requires_confirmation_for_email_send(fake_home):
    ensure_governance_policy()
    now = datetime(2026, 4, 19, 10, 0, tzinfo=timezone.utc)

    decision = evaluate_action("email_send", "normal", now)

    assert decision.permission == "ask_first"
    assert decision.requires_confirmation is True
    assert "requires confirmation" in decision.reason


def test_governance_notification_defers_non_urgent_during_quiet_hours(fake_home):
    policy = GovernancePolicy(quiet_hours_start="23:00", quiet_hours_end="08:00")
    save_governance_policy(policy)
    now = datetime(2026, 4, 19, 23, 30, tzinfo=timezone.utc)

    decision = evaluate_notification("email", "normal", now)

    assert decision.notification == "defer"
    assert "quiet hours" in decision.reason


def test_governance_notification_allows_urgent_override_during_quiet_hours(fake_home):
    policy = GovernancePolicy(quiet_hours_start="23:00", quiet_hours_end="08:00", urgent_overrides_quiet_hours=True)
    save_governance_policy(policy)
    now = datetime(2026, 4, 19, 23, 30, tzinfo=timezone.utc)

    decision = evaluate_notification("calendar", "critical", now)

    assert decision.notification == "notify_now"


def test_create_and_resolve_approval_request_persists_state(fake_home):
    now = datetime(2026, 4, 29, 8, 0, tzinfo=timezone.utc)

    approval = create_approval_request(
        action_type="email_send",
        summary="Send investor update",
        payload={"to": "investor@example.com"},
        user_id="approval-user",
        now=now,
    )

    fetched = get_approval_request(approval.approval_id, user_id="approval-user", now=now)
    assert fetched is not None
    assert fetched.status == "pending"
    assert fetched.payload["to"] == "investor@example.com"
    assert "Approval requested." in (fetched.prompt or "")

    resolved, error = resolve_approval_request(
        approval.approval_id,
        decision="approved",
        user_id="approval-user",
        resolved_by="ashish",
        reason="Looks correct",
        now=now + timedelta(minutes=1),
    )

    assert error is None
    assert resolved is not None
    assert resolved.status == "approved"
    assert resolved.resolved_by == "ashish"
    assert resolved.reason == "Looks correct"


def test_approval_request_expires_and_cannot_be_resolved(fake_home):
    now = datetime(2026, 4, 29, 8, 0, tzinfo=timezone.utc)
    approval = create_approval_request(
        action_type="public_post",
        summary="Post launch note",
        ttl_seconds=30,
        now=now,
    )

    expired = get_approval_request(approval.approval_id, now=now + timedelta(seconds=31))

    assert expired is not None
    assert expired.status == "expired"

    resolved, error = resolve_approval_request(
        approval.approval_id,
        decision="approved",
        now=now + timedelta(seconds=32),
    )

    assert error == "already_resolved"
    assert resolved is not None
    assert resolved.status == "expired"


def test_approval_request_uses_action_type_ttl_defaults(fake_home):
    now = datetime(2026, 4, 29, 8, 0, tzinfo=timezone.utc)

    email = create_approval_request(action_type="email_send", summary="Send email", now=now)
    calendar = create_approval_request(action_type="calendar_write", summary="Write calendar event", now=now)
    default = create_approval_request(action_type="unknown_action", summary="Do work", now=now)

    assert datetime.fromisoformat(email.expires_at) == now + timedelta(seconds=300)
    assert datetime.fromisoformat(calendar.expires_at) == now + timedelta(seconds=900)
    assert datetime.fromisoformat(default.expires_at) == now + timedelta(seconds=900)
