"""Platform App Standard v1 entrypoint for Australian ABN Lookup."""

from __future__ import annotations

from requests import RequestException

from apps.abn_lookup_app.abn_lookup_v1.models import AbnLookupError
from apps.abn_lookup_app.abn_lookup_v1.service import lookup_abn_v1
from apps.abn_lookup_app.core import lookup_abn_basic
from bridge_platform.apps.contracts import (
    ActionContract,
    AgentCapabilityContract,
    AppManifest,
    CredentialField,
    WordPressPackageContract,
)
from bridge_platform.apps.envelopes import error_envelope, success_envelope
from bridge_platform.logging.platform_logger import get_platform_logger, log_structured
from bridge_platform.secrets.encryption import SecretConfigurationError
from bridge_platform.secrets.secrets_manager import SecretsManager


LOGGER = get_platform_logger("abn_lookup_app")


APP_MANIFEST = AppManifest(
    app_id="abn_lookup_app",
    display_name="ABN Lookup",
    app_version="1.0.0",
    description="Look up Australian Business Register records by ABN.",
    credentials=(
        CredentialField(
            name="abr_lookup_guid",
            label="ABR authentication GUID",
            help_text="Issued by the Australian Business Register.",
        ),
    ),
    actions={
        "health_v1": ActionContract(
            capability="platform.health",
            description="Report local app health without contacting ABR.",
            output_schema={"type": "object", "required": ["healthy", "credential_configured"]},
            errors=(),
        ),
        "test_connection_v1": ActionContract(
            capability="platform.credentials.test",
            description="Validate the tenant ABR GUID with a minimal lookup.",
            required_credentials=("abr_lookup_guid",),
            output_schema={"type": "object", "required": ["connected", "provider"]},
            timeout_seconds=20,
            errors=("credential_not_configured", "provider_connection_failed"),
        ),
        "lookup_v1": ActionContract(
            capability="business.au.abn.lookup",
            description="Return one normalized Australian Business Register record.",
            input_schema={
                "type": "object",
                "additionalProperties": False,
                "required": ["abn"],
                "properties": {
                    "abn": {
                        "type": "string",
                        "pattern": "^[0-9]{11}$",
                        "description": "Exact 11-digit Australian Business Number.",
                    },
                    "include_history": {"type": "boolean", "default": False},
                },
            },
            output_schema={"type": "object", "required": ["abn", "record"]},
            required_credentials=("abr_lookup_guid",),
            timeout_seconds=20,
            data_classification="business",
            errors=(
                "invalid_input",
                "invalid_abn",
                "credential_not_configured",
                "provider_unavailable",
                "provider_invalid_response",
            ),
            agent=AgentCapabilityContract(
                exposed=True,
                title="Look up an Australian ABN",
                summary="Retrieve the normalized ABR record for an exact 11-digit ABN.",
                domains=("australian_business_registry", "supplier_verification"),
                use_when=(
                    "The user provides an exact Australian Business Number.",
                    "The user asks to validate an Australian business registration.",
                ),
                do_not_use_when=(
                    "The user provides only a business name.",
                    "The request is unrelated to an Australian business.",
                ),
                risk_category="read",
                risk_level="low",
                confirmation="never",
                required_permissions=("abn_lookup.read",),
            ),
        ),
    },
    wordpress_package=WordPressPackageContract(
        package_id="abn_lookup_wp",
        version="1.1.1-dev",
        source_directory="wordpress-pack/abn-lookup-wp",
        entrypoint="abn-lookup-wp.php",
        plugin_file="abn-lookup-wp/abn-lookup-wp.php",
        capabilities=("business.au.abn.lookup",),
    ),
)


def handle_request(context, action):
    """Dispatch standard actions and preserve legacy action compatibility."""
    if action == "test":
        return _legacy_health(context)
    if action == "lookup":
        return _legacy_lookup(context)
    if action == "health_v1":
        return _health(context)
    if action == "test_connection_v1":
        return _test_connection(context)
    if action == "lookup_v1":
        return _lookup(context)
    return error_envelope(
        app_id=APP_MANIFEST.app_id,
        action=action,
        request_id=_request_id(context),
        code="action_not_found",
        message="The requested action is not supported.",
    ), 404


def _health(context):
    configured = False
    vault_ready = True
    try:
        configured = _guid(context) is not None
    except SecretConfigurationError:
        vault_ready = False
    return success_envelope(
        app_id=APP_MANIFEST.app_id,
        action="health_v1",
        request_id=_request_id(context),
        data={
            "healthy": True,
            "vault_ready": vault_ready,
            "credential_configured": configured,
            "provider_checked": False,
        },
    )


def _test_connection(context):
    guid = _guid(context)
    if not guid:
        return _credential_missing(context, "test_connection_v1")
    probe_abn = str(((context or {}).get("payload") or {}).get("probe_abn") or "51824753556")
    try:
        record = lookup_abn_v1(probe_abn, guid=guid)
    except (RequestException, AbnLookupError):
        return error_envelope(
            app_id=APP_MANIFEST.app_id,
            action="test_connection_v1",
            request_id=_request_id(context),
            code="provider_connection_failed",
            message="ABR credentials could not be validated.",
            retryable=True,
        ), 502
    return success_envelope(
        app_id=APP_MANIFEST.app_id,
        action="test_connection_v1",
        request_id=_request_id(context),
        data={
            "connected": bool(record.get("abn")),
            "provider": "Australian Business Register",
            "probe_abn": probe_abn,
        },
    )


def _lookup(context):
    payload = (context or {}).get("payload") or {}
    abn = str(payload.get("abn") or "").strip()
    if not abn:
        return error_envelope(
            app_id=APP_MANIFEST.app_id,
            action="lookup_v1",
            request_id=_request_id(context),
            code="invalid_input",
            message="abn is required.",
        ), 400
    guid = _guid(context)
    if not guid:
        return _credential_missing(context, "lookup_v1")
    try:
        record = lookup_abn_v1(
            abn, include_history=bool(payload.get("include_history")), guid=guid,
        )
    except AbnLookupError:
        _log_lookup(context, abn, "rejected", error_code="invalid_abn")
        return error_envelope(
            app_id=APP_MANIFEST.app_id, action="lookup_v1",
            request_id=_request_id(context), code="invalid_abn",
            message="ABN must contain exactly 11 digits.",
        ), 400
    except RequestException:
        _log_lookup(context, abn, "failed", error_code="provider_unavailable")
        return error_envelope(
            app_id=APP_MANIFEST.app_id, action="lookup_v1",
            request_id=_request_id(context), code="provider_unavailable",
            message="Australian Business Register is temporarily unavailable.",
            retryable=True,
        ), 502
    if not record.get("abn"):
        _log_lookup(context, abn, "failed", error_code="provider_invalid_response")
        return error_envelope(
            app_id=APP_MANIFEST.app_id, action="lookup_v1",
            request_id=_request_id(context), code="provider_invalid_response",
            message="Australian Business Register returned an incomplete record.",
            retryable=True,
        ), 502
    _log_lookup(context, abn, "succeeded", status=record.get("status"))
    return success_envelope(
        app_id=APP_MANIFEST.app_id,
        action="lookup_v1",
        request_id=_request_id(context),
        data={"abn": abn.replace(" ", ""), "record": record},
        meta={"provider": "Australian Business Register"},
    )


def _guid(context) -> str | None:
    tenant_id = str((((context or {}).get("tenant") or {}).get("tenant_id")) or "")
    if not tenant_id:
        return None
    return SecretsManager().get_secret(
        tenant_id=tenant_id,
        app_id=APP_MANIFEST.app_id,
        secret_name="abr_lookup_guid",
    )


def _credential_missing(context, action):
    return error_envelope(
        app_id=APP_MANIFEST.app_id, action=action,
        request_id=_request_id(context), code="credential_not_configured",
        message="ABR credentials are not configured for this tenant.",
    ), 409


def _request_id(context) -> str:
    return str((context or {}).get("request_id") or "")


def _log_lookup(context, abn: str, outcome: str, **fields) -> None:
    normalized = "".join(character for character in str(abn) if character.isdigit())
    log_structured(
        LOGGER,
        "abn_lookup_result",
        request_id=_request_id(context),
        tenant_id=str((((context or {}).get("tenant") or {}).get("tenant_id")) or ""),
        outcome=outcome,
        abn_suffix=normalized[-4:] if normalized else "",
        **fields,
    )


def _legacy_health(context):
    return {
        "status": "ok", "app": APP_MANIFEST.app_id,
        "tenant": ((context or {}).get("tenant") or {}).get("tenant_id"),
    }


def _legacy_lookup(context):
    """Temporary v0 response retained until wp_invoices migrates."""
    payload = (context or {}).get("payload") or {}
    abn = str(payload.get("abn") or "").strip()
    if not abn:
        return {"status": "error", "app": APP_MANIFEST.app_id, "message": "Missing abn"}, 400
    guid = _guid(context)
    if not guid:
        return {
            "status": "error", "app": APP_MANIFEST.app_id,
            "message": "ABR credential is not configured",
        }, 409
    data = lookup_abn_basic(abn, guid=guid)
    return {
        "status": "ok", "app": APP_MANIFEST.app_id, "action": "lookup",
        "result": {
            "abn": data.get("tax_id") or abn,
            "valid": bool(data.get("abn_exists")),
            "data": data,
        },
    }
