"""Plaid Finance plugin — adapter that satisfies the FinanceProvider protocol.

Connects multiple banks via Plaid Link. Implements get_balances, list_accounts,
get_transactions. Mercury remains default; Plaid is additive.
"""

from __future__ import annotations

from typing import Any

__all__ = [
    "PlaidFinanceAdapter",
    "format_balance",
    "format_transactions",
]


def _load_plaid_config(project_root: Any = None) -> dict:
    """Load Plaid config from env or config/local/plaid_credentials.yaml."""
    import os
    from pathlib import Path

    if project_root is None:
        project_root = Path(__file__).resolve().parents[3]
    from vastian.storage.data_root import get_config_dir

    cfg_path = get_config_dir(project_root) / "local" / "plaid_credentials.yaml"
    client_id = os.environ.get("PLAID_CLIENT_ID", "")
    secret = os.environ.get("PLAID_SECRET", "")
    env_name = os.environ.get("PLAID_ENV", "sandbox")
    access_tokens: list[str] = []
    if cfg_path.exists():
        try:
            import yaml

            data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) or {}
            client_id = client_id or data.get("client_id", "")
            secret = secret or data.get("secret", "")
            env_name = data.get("environment", env_name)
            for item in data.get("items", []):
                tok = item.get("access_token") if isinstance(item, dict) else None
                if tok:
                    access_tokens.append(tok)
        except Exception:
            pass
    return {
        "client_id": client_id,
        "secret": secret,
        "environment": env_name,
        "access_tokens": access_tokens,
    }


class PlaidFinanceAdapter:
    """Adapter that wraps PlaidClient and satisfies the FinanceProvider protocol."""

    def __init__(
        self,
        client_id: str = "",
        secret: str = "",
        environment: str = "sandbox",
        access_tokens: list[str] | None = None,
        project_root: Any = None,
    ) -> None:
        if not client_id or not secret:
            cfg = _load_plaid_config(project_root)
            client_id = client_id or cfg["client_id"]
            secret = secret or cfg["secret"]
            environment = cfg["environment"]
            access_tokens = access_tokens or cfg["access_tokens"]
        try:
            from vastian.integrations.plaid import PlaidClient

            self._client = PlaidClient(
                client_id=client_id,
                secret=secret,
                environment=environment,
                access_tokens=access_tokens,
            )
        except ImportError as e:
            self._client = None
            self._import_error = str(e)
        else:
            self._import_error = None

    @property
    def is_configured(self) -> bool:
        return self._client is not None and self._client.is_configured

    async def get_balances(self) -> list[dict]:
        """Get balances for all configured Plaid accounts."""
        if not self._client:
            return []
        return await self._client.get_all_balances()

    async def list_accounts(self) -> list[dict]:
        """List all Plaid accounts with metadata."""
        if not self._client:
            return []
        return await self._client.get_accounts()

    async def get_transactions(
        self,
        account_id: str,
        start_date: str | None = None,
        end_date: str | None = None,
    ) -> list[dict]:
        """Get transactions for a Plaid account."""
        if not self._client:
            return []
        from datetime import date

        sd = date.fromisoformat(start_date[:10]) if start_date else None
        ed = date.fromisoformat(end_date[:10]) if end_date else None
        return await self._client.list_transactions(
            account_id=account_id,
            limit=100,
            start_date=sd,
            end_date=ed,
        )

    def format_balance(self, account: dict[str, Any]) -> str:
        """Human-readable balance summary."""
        if self._client:
            return self._client.format_balance(account)
        return f"**{account.get('name', 'Account')}** — Plaid (not configured)"

    def format_transactions(self, txns: list[dict[str, Any]], limit: int = 10) -> str:
        """Human-readable transaction list."""
        if self._client:
            return self._client.format_transactions(txns, limit)
        return "No transactions (Plaid not configured)"


# Module-level exports for compatibility
def format_balance(account: dict[str, Any]) -> str:
    from vastian.integrations.plaid import PlaidClient

    return PlaidClient.format_balance(account)


def format_transactions(txns: list[dict[str, Any]], limit: int = 10) -> str:
    from vastian.integrations.plaid import PlaidClient

    return PlaidClient.format_transactions(txns, limit)


def register() -> None:
    """Register the Plaid finance plugin with the loader."""
    from vastian.loader import register as loader_register

    loader_register("plaid_finance", PlaidFinanceAdapter)
