"""金融连接器已接受持久化事件的商业计量边界。"""

from __future__ import annotations

import hashlib
from dataclasses import dataclass
from datetime import UTC, datetime

from sqlalchemy.orm import Session, sessionmaker

from app.services.commercial_direct_operation import (
    CommercialDirectOperationBridge,
    DirectOperationIdentity,
    DirectOperationResult,
)
from app.services.commercial_transaction_callbacks import (
    bind_commercial_transaction_outcome,
)
from app.services.tenant_registry import required_tenant_id


class FinancialConnectorCommercialAccessDenied(RuntimeError):
    pass


@dataclass(frozen=True, slots=True)
class FinancialConnectorCommercialAttempt:
    identity: DirectOperationIdentity


class FinancialConnectorCommercialObserver:
    """只在认证、去重之后预占，并在业务事件提交后结算一个 event。"""

    def __init__(self, bridge: CommercialDirectOperationBridge) -> None:
        self.bridge = bridge

    def permit(
        self,
        *,
        tenant_id: str,
        config_id: str,
        provider: str,
        request_fingerprint: str,
        received_at: datetime,
    ) -> FinancialConnectorCommercialAttempt:
        tenant = required_tenant_id(tenant_id)
        fingerprint = _sha256_token(request_fingerprint)
        config_token = _sha256_token(config_id)
        identity = DirectOperationIdentity(
            tenant_id=tenant,
            operation_key=f"financial-ingest:{config_token}:{fingerprint}",
            run_key=f"financial-ingest-run:{fingerprint}",
            tool_type="connector",
            tool_name="financial.ingest",
            provider=str(provider or "").strip() or None,
            started_at=_utc(received_at),
        )
        permit = self.bridge.permit(
            identity,
            requested_quantity=1,
            required_quantity_basis="events",
        )
        if not permit.allowed:
            raise FinancialConnectorCommercialAccessDenied(permit.reason)
        return FinancialConnectorCommercialAttempt(identity=identity)

    def bind_to_transaction(
        self,
        db: Session,
        attempt: FinancialConnectorCommercialAttempt,
    ) -> None:
        bind_commercial_transaction_outcome(
            db,
            on_commit=lambda: self.complete(attempt),
            on_rollback=lambda: self.release(attempt),
            operation_name="financial_connector_ingestion",
        )

    def complete(
        self,
        attempt: FinancialConnectorCommercialAttempt,
    ) -> DirectOperationResult:
        return self.bridge.complete(
            attempt.identity,
            outcome="succeeded",
            authoritative_quantities={"events": 1},
            completed_at=datetime.now(UTC),
            usage_source="persisted_financial_connector_event",
            usage_availability="available",
        )

    def release(
        self,
        attempt: FinancialConnectorCommercialAttempt,
    ) -> DirectOperationResult:
        return self.bridge.complete(
            attempt.identity,
            outcome="not_sent",
            authoritative_quantities={},
            completed_at=datetime.now(UTC),
            usage_source="business_transaction_rolled_back",
            usage_availability="unavailable",
        )


def build_financial_connector_commercial_observer(
    db: Session,
) -> FinancialConnectorCommercialObserver:
    factory = sessionmaker(bind=db.get_bind(), expire_on_commit=False)
    return FinancialConnectorCommercialObserver(
        CommercialDirectOperationBridge(factory, lookup_session=db)
    )


def _sha256_token(value: str) -> str:
    normalized = str(value or "").strip()
    if not normalized:
        raise ValueError("连接器商业计量身份缺少可信摘要字段。")
    return hashlib.sha256(normalized.encode("utf-8")).hexdigest()


def _utc(value: datetime) -> datetime:
    return value.replace(tzinfo=UTC) if value.tzinfo is None else value.astimezone(UTC)
