"""TRON Shasta testnet USDT (TRC-20) integration.

This module deliberately supports Shasta testnet only. It signs transactions
locally with a dedicated TESTNET private key supplied through the environment.
Never put a production private key in source control.
"""
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils import timezone
import hashlib
import re
import time

TRON_NETWORK = "shasta"
USDT_DECIMALS = 6


def mock_enabled():
    return bool(getattr(settings, "TRON_MOCK_MODE", False))


def _client():
    # Local mock mode deliberately requires no wallet or private key.
    # It never contacts TRON and never signs or broadcasts a transaction.
    if mock_enabled():
        return None, None
    if settings.TRON_ENABLE_MAINNET:
        raise ValidationError("Mainnet is disabled in this testnet build.")
    if settings.TRON_NETWORK != TRON_NETWORK:
        raise ValidationError("Only TRON Shasta testnet is enabled by this build.")
    if not settings.TRON_PRIVATE_KEY:
        raise ValidationError("TRON_PRIVATE_KEY is not configured.")
    if not settings.TRON_RPC_URL.startswith("https://api.shasta.trongrid.io"):
        raise ValidationError("TRON Shasta RPC endpoint is required for testnet mode.")
    try:
        from tronpy import Tron
        from tronpy.keys import PrivateKey
        from tronpy.providers import HTTPProvider
    except ImportError as exc:
        raise ValidationError("tronpy is not installed. Run: pip install -r requirements.txt") from exc
    try:
        key = PrivateKey(bytes.fromhex(settings.TRON_PRIVATE_KEY))
    except Exception as exc:
        raise ValidationError("TRON_PRIVATE_KEY must be a 64-character hexadecimal Shasta test key.") from exc
    return Tron(provider=HTTPProvider(settings.TRON_RPC_URL), network="shasta"), key


def validate_tron_address(address):
    if mock_enabled():
        # Local-only test addresses: TRON-shaped Base58 strings are accepted
        # without contacting the blockchain. Nothing is sent on-chain.
        return bool(re.fullmatch(r"T[1-9A-HJ-NP-Za-km-z]{33}", str(address or "")))
    try:
        from tronpy.keys import is_address
        return bool(is_address(address))
    except Exception:
        return False


def send_usdt_testnet(recipient_address: str, amount_minor: int):
    """Submit a USDT transfer. In local mock mode this never contacts TRON."""
    if amount_minor <= 0:
        raise ValidationError("USDT amount must be greater than zero.")
    if not validate_tron_address(recipient_address):
        raise ValidationError("Invalid TRON recipient address.")

    if mock_enabled():
        mock_balance = int(getattr(settings, "TRON_MOCK_USDT_BALANCE_MINOR", 1_000_000_000))
        if amount_minor > mock_balance:
            raise ValidationError("Mock Shasta settlement wallet has insufficient test USDT.")
        seed = f"mock-shasta:{recipient_address}:{amount_minor}:{time.time_ns()}".encode()
        txid = hashlib.sha256(seed).hexdigest()
        return {
            "txid": txid,
            "owner": "TMOCKSettlementWallet000000000000000",
            "network": "TRON-Shasta-MOCK",
            "contract": settings.TRON_USDT_CONTRACT,
            "submitted_at": timezone.now(),
            "mock": True,
        }

    client, private_key = _client()
    owner = private_key.public_key.to_base58check_address()
    if recipient_address == owner:
        raise ValidationError("Recipient cannot be the settlement wallet itself.")

    contract = client.get_contract(settings.TRON_USDT_CONTRACT)
    try:
        token_decimals = int(contract.functions.decimals())
    except Exception as exc:
        raise ValidationError("Could not read the configured USDT contract decimals.") from exc
    if token_decimals != USDT_DECIMALS:
        raise ValidationError("Configured TRON USDT contract does not use 6 decimals.")
    try:
        onchain_balance = int(contract.functions.balanceOf(owner))
    except Exception as exc:
        raise ValidationError("Could not read the settlement wallet USDT balance.") from exc
    if onchain_balance < amount_minor:
        raise ValidationError("Settlement wallet has insufficient testnet USDT.")
    try:
        txn = (contract.functions.transfer(recipient_address, amount_minor)
               .with_owner(owner).fee_limit(settings.TRON_FEE_LIMIT_SUN).build().sign(private_key))
        result = txn.broadcast()
        if not result.get("result"):
            raise ValidationError(f"TRON broadcast failed: {result}")
        txid = result.get("txid") or txn.txid
    except ValidationError:
        raise
    except Exception as exc:
        raise ValidationError(f"TRON transaction submission failed: {exc}") from exc
    return {
        "txid": txid, "owner": owner, "network": "TRON-Shasta",
        "contract": settings.TRON_USDT_CONTRACT, "submitted_at": timezone.now(), "mock": False,
    }


def get_transaction_status(txid: str):
    """Return confirmed/failed state. Mock mode confirms locally without blockchain access."""
    if mock_enabled():
        return {
            "found": True, "confirmed": True, "confirmations": max(1, settings.TRON_CONFIRMATIONS),
            "block_number": 0, "result": "SUCCESS",
            "raw": {"mock": True, "txid": txid},
        }
    client, _ = _client()
    try:
        info = client.get_transaction_info(txid)
        if not info:
            return {"found": False, "confirmed": False, "confirmations": 0, "raw": {}}
        receipt = info.get("receipt") or {}
        result = receipt.get("result") or ""
        block_number = info.get("blockNumber")
        confirmed = False
        confirmations = 0
        if block_number and result in {"", "SUCCESS"}:
            try:
                latest = client.get_latest_block_number()
                confirmations = max(0, int(latest) - int(block_number) + 1)
                confirmed = confirmations >= max(1, settings.TRON_CONFIRMATIONS)
            except Exception:
                confirmations = 1
                confirmed = settings.TRON_CONFIRMATIONS <= 1
        return {
            "found": True,
            "confirmed": confirmed,
            "confirmations": confirmations,
            "block_number": block_number,
            "result": result,
            "raw": info,
        }
    except Exception as exc:
        raise ValidationError(f"Could not query TRON transaction: {exc}") from exc
