"""Tests for Phase 5 SP5 investment audit fixes.

Coverage:
* FRSME-INV012 — auto-share dashboard on accept; investor receives a share
  and a DashboardAccessLog row is created.
* FRSME-INV012 — share_dashboard_with_investor sets ``expires_at`` so a
  leaked URL has bounded blast radius. Settings-driven via
  ``SMEHUB_DASHBOARD_SHARE_TTL_DAYS``.
* FRSME-INV012 — DashboardAccessLog.is_active flips False on revoke or
  expiry; the view rejects stale tokens.
* FRSME-INV008 — investor matchmaker now uses ``Investor.investment_stages``
  instead of an empty list (audit fix).
"""
from __future__ import annotations

from datetime import timedelta
from decimal import Decimal

import pytest
from django.contrib.auth import get_user_model
from django.test import override_settings
from django.utils import timezone

from apps.core.permissions.roles import UserRole
from apps.smehub.investment import services
from apps.smehub.investment.models import (
    DashboardAccessLog,
    Investor,
    InvestorConnectionRequest,
)
from apps.smehub.onboarding.models import (
    Business,
    BusinessStage,
    EntrepreneurProfile,
)

User = get_user_model()
pytestmark = pytest.mark.django_db


@pytest.fixture
def admin():
    return User.objects.create_user(
        email="adm-p5@example.com", password="x",
        is_superuser=True, is_staff=True, role=UserRole.SYSTEM_ADMIN,
    )


@pytest.fixture
def entrepreneur(admin):
    user = User.objects.create_user(
        email="ent-p5@example.com", password="x", role=UserRole.ENTREPRENEUR,
    )
    profile = EntrepreneurProfile.objects.create(user=user, country="KE")
    profile.verify(by_user=admin)
    profile.save()
    return profile


@pytest.fixture
def verified_business(entrepreneur, admin):
    biz = Business.objects.create(
        entrepreneur=entrepreneur,
        name="P5 Co",
        sector="Agriculture",
        business_stage=BusinessStage.MVP,
        country="KE",
    )
    biz.verify(by_user=admin)
    biz.save()
    return biz


@pytest.fixture
def investor_user():
    return User.objects.create_user(
        email="inv-p5@example.com", password="x", role=UserRole.INVESTOR,
    )


@pytest.fixture
def verified_investor(admin, investor_user):
    inv = services.create_investor(
        by_user=admin,
        org_name="P5 Capital",
        type=Investor.Type.VC,
        investment_focus=["Agriculture"],
        geographic_preference=["KE"],
        contact_user=investor_user,
        auto_verify=True,
    )
    return Investor.objects.get(pk=inv.pk)


# ---------------------------------------------------------------------------
# FRSME-INV012 — auto-share on accept
# ---------------------------------------------------------------------------

def test_accept_investor_request_auto_shares_dashboard(
    entrepreneur, verified_business, verified_investor, investor_user,
):
    """Audit fix: PRD says the dashboard is shared *upon acceptance*. The
    audit found this was a separate manual entrepreneur action."""
    request = services.request_investor_connection(
        entrepreneur=entrepreneur,
        business=verified_business,
        investor=verified_investor,
        message="Pitch P5",
    )
    assert DashboardAccessLog.objects.filter(
        entrepreneur=entrepreneur, investor=verified_investor,
    ).count() == 0

    services.accept_investor_request(request, by_user=investor_user)

    log = DashboardAccessLog.objects.filter(
        entrepreneur=entrepreneur, investor=verified_investor,
    ).first()
    assert log is not None
    assert log.expires_at is not None
    assert log.is_active is True


def test_accept_request_skips_share_when_investor_unverified(
    entrepreneur, verified_business, admin, investor_user,
):
    """A best-effort path: if the investor lost VERIFIED before accept,
    the deal-room still opens but no share is created."""
    inv = services.create_investor(
        by_user=admin, org_name="Pending Co", type=Investor.Type.ANGEL,
        contact_user=investor_user,
    )  # left in PENDING
    request = InvestorConnectionRequest.objects.create(
        entrepreneur=entrepreneur,
        business=verified_business,
        investor=inv,
        message="x",
    )
    # Force-verify so the deal-room can open, then immediately drop to deactivated
    services.verify_investor(inv, by_user=admin)
    inv = Investor.objects.get(pk=inv.pk)
    inv.deactivate(reason="audit")
    inv.save()

    # accept_investor_request should still work (deal room opens) even
    # though the auto-share will fail silently.
    services.accept_investor_request(request, by_user=investor_user)
    assert DashboardAccessLog.objects.filter(entrepreneur=entrepreneur, investor=inv).count() == 0


# ---------------------------------------------------------------------------
# FRSME-INV012 — share TTL is bounded + settings-driven
# ---------------------------------------------------------------------------

@override_settings(SMEHUB_DASHBOARD_SHARE_TTL_DAYS=14)
def test_share_dashboard_uses_settings_driven_ttl(
    entrepreneur, verified_investor,
):
    log = services.share_dashboard_with_investor(
        entrepreneur=entrepreneur, investor=verified_investor,
    )
    delta = log.expires_at - log.accessed_at
    # Allow a small tolerance for the seconds between log creation and assertion.
    assert timedelta(days=13, hours=23) < delta < timedelta(days=14, minutes=2)


def test_share_dashboard_default_ttl_is_about_90_days(entrepreneur, verified_investor):
    log = services.share_dashboard_with_investor(
        entrepreneur=entrepreneur, investor=verified_investor,
    )
    delta = log.expires_at - log.accessed_at
    assert timedelta(days=89) < delta < timedelta(days=91)


# ---------------------------------------------------------------------------
# FRSME-INV012 — share lifecycle (active / expired / revoked)
# ---------------------------------------------------------------------------

def test_dashboard_access_log_is_active_until_expiry(entrepreneur, verified_investor):
    log = services.share_dashboard_with_investor(
        entrepreneur=entrepreneur, investor=verified_investor,
    )
    assert log.is_active is True

    # Expire by rolling the clock forward.
    DashboardAccessLog.objects.filter(pk=log.pk).update(
        expires_at=timezone.now() - timedelta(seconds=1),
    )
    refreshed = DashboardAccessLog.objects.get(pk=log.pk)
    assert refreshed.is_active is False


def test_dashboard_access_log_is_inactive_after_revoke(entrepreneur, verified_investor):
    log = services.share_dashboard_with_investor(
        entrepreneur=entrepreneur, investor=verified_investor,
    )
    DashboardAccessLog.objects.filter(pk=log.pk).update(revoked_at=timezone.now())
    refreshed = DashboardAccessLog.objects.get(pk=log.pk)
    assert refreshed.is_active is False


# ---------------------------------------------------------------------------
# FRSME-INV008 — investor matchmaker stages
# ---------------------------------------------------------------------------

def test_investor_payload_includes_investment_stages():
    """Audit found ``stages`` was hard-coded ``[]`` in ``_investor_payload``;
    the 15% stage weight never fired."""
    inv = Investor.objects.create(
        org_name="Stage Co",
        type=Investor.Type.VC,
        investment_focus=["Agriculture"],
        investment_stages=["mvp", "early_revenue"],
    )
    inv.verify(by_user=None)
    inv.save()
    payload = services._investor_payload([inv])
    assert payload[0]["stages"] == ["mvp", "early_revenue"]
