"""
Fee Settlement Services — encryption/decryption + account lifecycle.
"""
import base64
import logging
import os
from typing import Optional, Tuple

from fastapi import HTTPException, status
from sqlalchemy.orm import Session

from src.apps.admin.models.hw_platform_bank_account import HWPlatformBankAccount
from src.apps.fee_settlement.crud import (
    create_settlement_account_record,
    deactivate_all_settlement_accounts,
    get_settlement_account_by_id,
    soft_delete_settlement_account,
)
from src.apps.fee_settlement.schemas.settlement_account import SettlementAccountCreate
from src.core.config import settings

logger = logging.getLogger(__name__)

# ─── Encryption helpers ───────────────────────────────────────────────────────

def _get_encryption_key() -> bytes:
    """Return 32-byte AES key decoded from SETTLEMENT_ACCOUNT_ENCRYPTION_KEY env var."""
    raw = getattr(settings, "SETTLEMENT_ACCOUNT_ENCRYPTION_KEY", None)
    if not raw:
        raise RuntimeError(
            "SETTLEMENT_ACCOUNT_ENCRYPTION_KEY is not configured. "
            "Generate a 32-byte base64 key: "
            "python -c \"import base64,os; print(base64.b64encode(os.urandom(32)).decode())\""
        )
    key = base64.b64decode(raw)
    if len(key) != 32:
        raise RuntimeError("SETTLEMENT_ACCOUNT_ENCRYPTION_KEY must decode to exactly 32 bytes")
    return key


def encrypt_field(plaintext: str) -> str:
    """
    Encrypt a plaintext string using AES-256-GCM.
    Returns base64-encoded (nonce + ciphertext) string for storage.
    """
    from cryptography.hazmat.primitives.ciphers.aead import AESGCM

    key = _get_encryption_key()
    nonce = os.urandom(12)  # 96-bit nonce recommended for GCM
    aesgcm = AESGCM(key)
    ciphertext = aesgcm.encrypt(nonce, plaintext.encode("utf-8"), None)
    return base64.b64encode(nonce + ciphertext).decode("utf-8")


def decrypt_field(enc_b64: str) -> str:
    """
    Decrypt a base64-encoded (nonce + ciphertext) string stored by encrypt_field().
    Returns the original plaintext.
    """
    from cryptography.hazmat.primitives.ciphers.aead import AESGCM

    key = _get_encryption_key()
    raw = base64.b64decode(enc_b64)
    nonce = raw[:12]
    ciphertext = raw[12:]
    aesgcm = AESGCM(key)
    return aesgcm.decrypt(nonce, ciphertext, None).decode("utf-8")


# ─── Settlement Account service layer ────────────────────────────────────────

def create_settlement_account(
    db: Session,
    data: SettlementAccountCreate,
    created_by_user_id: Optional[int] = None,
) -> Tuple[HWPlatformBankAccount, list]:
    """
    Atomic swap:
      1. Deactivate all existing accounts (returns list for audit logging).
      2. Encrypt routing/account numbers.
      3. Insert new active account.
      4. Commit.

    Returns (new_account, deactivated_accounts) so the caller can write audit log entries.
    """
    routing_enc = encrypt_field(data.routing_number)
    account_enc = encrypt_field(data.account_number)
    last4 = data.account_number[-4:]

    # Atomic swap — collect accounts to deactivate before the UPDATE
    deactivated_orm = deactivate_all_settlement_accounts(db)
    # Snapshot audit fields before db.commit() expires ORM objects
    deactivated = [
        {"id": a.id, "nickname": a.nickname, "account_number_last4": a.account_number_last4}
        for a in deactivated_orm
    ]

    account = create_settlement_account_record(
        db=db,
        nickname=data.nickname,
        account_holder_name=data.account_holder_name,
        bank_name=data.bank_name,
        routing_number_enc=routing_enc,
        account_number_enc=account_enc,
        account_number_last4=last4,
        account_type=data.account_type,
        created_by_user_id=created_by_user_id,
    )
    db.commit()
    db.refresh(account)
    return account, deactivated


def delete_settlement_account(
    db: Session,
    account_id: int,
) -> None:
    """Soft-delete a settlement account. Raises 404 if not found."""
    account = get_settlement_account_by_id(db, account_id)
    if not account:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Settlement account not found",
        )
    soft_delete_settlement_account(db, account)
    db.commit()


def get_decrypted_account_credentials(account: HWPlatformBankAccount) -> Tuple[str, str]:
    """Return (routing_number, account_number) plaintext. For use in task only."""
    routing = decrypt_field(account.routing_number_enc)
    account_num = decrypt_field(account.account_number_enc)
    return routing, account_num
