"""Standalone billing signature, idempotency, and lifecycle checks."""

from __future__ import annotations

import hashlib
import hmac
import json
import os
import sys
import time
import unittest
from datetime import datetime, timedelta, timezone
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
loaded_platform = sys.modules.get("platform")
if loaded_platform is not None and not hasattr(loaded_platform, "__path__"):
    del sys.modules["platform"]

from sqlalchemy import create_engine, select
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool

from config.db import Base
from platform.billing import webhooks
from platform.billing import stripe_adapter
from platform.billing.lifecycle import evaluate_subscription
from platform.tenants.models import (
    BillingProductMapping,
    BillingWebhookEvent,
    Plan,
    Tenant,
    TenantSubscription,
)


class BillingChecks(unittest.TestCase):
    def setUp(self):
        self.engine = create_engine(
            "sqlite://", connect_args={"check_same_thread": False},
            poolclass=StaticPool, future=True,
        )
        Base.metadata.create_all(self.engine)
        self.original_factory = webhooks.get_control_plane_session
        webhooks.get_control_plane_session = lambda: Session(self.engine, future=True)
        with Session(self.engine, future=True) as session:
            session.add(Plan(plan_id="paid", code="paid", name="Paid"))
            session.add(Tenant(
                tenant_id="tenant-a", slug="tenant-a", name="Tenant A",
                status="active", is_active=True,
            ))
            session.add(BillingProductMapping(
                provider="adapter", price_id="price-paid", plan_id="paid",
            ))
            session.commit()

    def tearDown(self):
        webhooks.get_control_plane_session = self.original_factory
        os.environ.pop("BILLING_WEBHOOK_SECRET_ADAPTER", None)
        os.environ.pop("STRIPE_WEBHOOK_SECRET", None)
        self.engine.dispose()

    def test_signature_accepts_current_message_and_rejects_tampering(self):
        os.environ["BILLING_WEBHOOK_SECRET_ADAPTER"] = "test-secret"
        body = b'{"id":"event-1"}'
        timestamp = str(int(time.time()))
        signature = hmac.new(
            b"test-secret", timestamp.encode() + b"." + body, hashlib.sha256,
        ).hexdigest()
        webhooks.verify_signature("adapter", body, timestamp, signature)
        with self.assertRaises(webhooks.BillingWebhookError):
            webhooks.verify_signature("adapter", body + b"x", timestamp, signature)

    def test_event_creates_subscription_and_duplicate_is_idempotent(self):
        payload = {
            "id": "event-1",
            "type": "subscription.active",
            "data": {
                "tenant_id": "tenant-a",
                "customer_id": "customer-a",
                "subscription_id": "subscription-a",
                "price_id": "price-paid",
                "status": "active",
            },
        }
        raw = json.dumps(payload, separators=(",", ":")).encode()
        first = webhooks.process_event("adapter", payload, raw)
        second = webhooks.process_event("adapter", payload, raw)
        self.assertFalse(first["duplicate"])
        self.assertTrue(second["duplicate"])
        with Session(self.engine, future=True) as session:
            subscription = session.execute(select(TenantSubscription)).scalar_one()
            receipts = session.execute(select(BillingWebhookEvent)).scalars().all()
            self.assertEqual("active", subscription.status)
            self.assertEqual("paid", subscription.plan_id)
            self.assertEqual(1, len(receipts))

    def test_past_due_grace_expires(self):
        now = datetime.now(timezone.utc)
        allowed = evaluate_subscription(
            "past_due", {"grace_until": (now + timedelta(hours=1)).isoformat()}, now,
        )
        blocked = evaluate_subscription(
            "past_due", {"grace_until": (now - timedelta(seconds=1)).isoformat()}, now,
        )
        self.assertTrue(allowed["access_allowed"])
        self.assertTrue(allowed["in_grace_period"])
        self.assertFalse(blocked["access_allowed"])

    def test_native_stripe_signature_and_subscription_translation(self):
        os.environ["STRIPE_WEBHOOK_SECRET"] = "whsec_test"
        payload = {
            "id": "evt_stripe_1",
            "type": "customer.subscription.updated",
            "data": {"object": {
                "id": "sub_stripe_1",
                "customer": "cus_stripe_1",
                "status": "trialing",
                "metadata": {"tenant_id": "tenant-a"},
                "items": {"data": [{"price": {"id": "price-paid"}}]},
                "current_period_start": 1700000000,
                "current_period_end": 1702592000,
                "cancel_at_period_end": False,
            }},
        }
        raw = json.dumps(payload, separators=(",", ":")).encode()
        timestamp = int(time.time())
        signature = hmac.new(
            b"whsec_test", str(timestamp).encode() + b"." + raw, hashlib.sha256,
        ).hexdigest()
        stripe_adapter.verify_stripe_signature(raw, f"t={timestamp},v1={signature}")
        translated = stripe_adapter.translate_stripe_event(payload)
        self.assertEqual("subscription.trialing", translated["type"])
        self.assertEqual("tenant-a", translated["data"]["tenant_id"])
        self.assertEqual("price-paid", translated["data"]["price_id"])


if __name__ == "__main__":
    unittest.main(verbosity=2)
