#!/usr/bin/env python3
"""
Secure Custodial Tron ↔ ERUP Bridge
Invariant: ERUP_supply <= USDT_reserve
Production-oriented skeleton (persistent + idempotent)
"""

import os
import time
import json
import sqlite3
import hashlib
import logging
import threading
from dataclasses import dataclass
from typing import Optional, Dict
from enum import Enum

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


# =============================
# Exceptions
# =============================

class BridgeError(Exception):
    pass

class InvariantViolation(BridgeError):
    pass

class DuplicateTransaction(BridgeError):
    pass

class InsufficientReserve(BridgeError):
    pass


# =============================
# Status Enum
# =============================

class BridgeStatus(str, Enum):
    PENDING = "pending"
    CONFIRMED = "confirmed"
    COMPLETED = "completed"
    FAILED = "failed"


# =============================
# Bridge Core
# =============================

class TronBridge:

    CONFIRMATION_THRESHOLD = 20

    def __init__(self, db_path="bridge.db"):
        self._lock = threading.RLock()
        self.db = sqlite3.connect(db_path, check_same_thread=False)
        self._init_db()
        self._load_state()

        logger.info("Bridge started")
        logger.info(f"Reserve: {self.usdt_reserve}, Supply: {self.erup_supply}")

    # -------------------------
    # Database
    # -------------------------

    def _init_db(self):
        cur = self.db.cursor()
        cur.execute("""
        CREATE TABLE IF NOT EXISTS state (
            key TEXT PRIMARY KEY,
            value TEXT
        )
        """)
        cur.execute("""
        CREATE TABLE IF NOT EXISTS transactions (
            id TEXT PRIMARY KEY,
            direction TEXT,
            source_tx TEXT UNIQUE,
            amount INTEGER,
            fee INTEGER,
            status TEXT,
            confirmations INTEGER,
            created_at INTEGER
        )
        """)
        self.db.commit()

    def _load_state(self):
        cur = self.db.cursor()

        def get_value(k, default=0):
            cur.execute("SELECT value FROM state WHERE key=?", (k,))
            row = cur.fetchone()
            return int(row[0]) if row else default

        self.usdt_reserve = get_value("usdt_reserve", 0)
        self.erup_supply = get_value("erup_supply", 0)

    def _save_state(self):
        cur = self.db.cursor()
        cur.execute("REPLACE INTO state VALUES (?,?)", ("usdt_reserve", str(self.usdt_reserve)))
        cur.execute("REPLACE INTO state VALUES (?,?)", ("erup_supply", str(self.erup_supply)))
        self.db.commit()

    # -------------------------
    # Mint Flow (USDT → ERUP)
    # -------------------------

    def mint_from_usdt(self, source_tx: str, usdt_amount: int):
        with self._lock:

            if usdt_amount <= 0:
                raise BridgeError("Amount must be positive")

            # Idempotency check
            if self._is_source_processed(source_tx):
                raise DuplicateTransaction("Source tx already processed")

            fee = usdt_amount // 200  # 0.5%
            if fee < 1:
                fee = 1

            erup_amount = usdt_amount - fee

            # VERIFY TRON TX (stub – must implement real verification)
            self._verify_tron_deposit(source_tx, usdt_amount)

            # Update reserve
            self.usdt_reserve += usdt_amount
            self.erup_supply += erup_amount

            # Invariant check
            if self.erup_supply > self.usdt_reserve:
                raise InvariantViolation("ERUP_supply exceeded reserve")

            tx_id = hashlib.sha256(
                f"mint{source_tx}{time.time_ns()}".encode()
            ).hexdigest()

            self._store_tx(tx_id, "mint", source_tx, usdt_amount, fee)

            self._save_state()

            logger.info(f"Minted {erup_amount} ERUP")
            return {
                "tx_id": tx_id,
                "erup_minted": erup_amount,
                "reserve": self.usdt_reserve,
                "supply": self.erup_supply
            }

    # -------------------------
    # Burn Flow (ERUP → USDT)
    # -------------------------

    def burn_to_usdt(self, source_tx: str, erup_amount: int):
        with self._lock:

            if erup_amount <= 0:
                raise BridgeError("Amount must be positive")

            if self._is_source_processed(source_tx):
                raise DuplicateTransaction("Source tx already processed")

            fee = erup_amount // 200
            if fee < 1:
                fee = 1

            usdt_release = erup_amount - fee

            if usdt_release > self.usdt_reserve:
                raise InsufficientReserve("Not enough USDT reserve")

            # VERIFY ERUP BURN (stub – must verify on ERUP chain)
            self._verify_erup_burn(source_tx, erup_amount)

            self.usdt_reserve -= usdt_release
            self.erup_supply -= erup_amount

            if self.erup_supply > self.usdt_reserve:
                raise InvariantViolation("Invariant violated after burn")

            tx_id = hashlib.sha256(
                f"burn{source_tx}{time.time_ns()}".encode()
            ).hexdigest()

            self._store_tx(tx_id, "burn", source_tx, erup_amount, fee)

            self._save_state()

            logger.info(f"Released {usdt_release} USDT")
            return {
                "tx_id": tx_id,
                "usdt_released": usdt_release,
                "reserve": self.usdt_reserve,
                "supply": self.erup_supply
            }

    # -------------------------
    # Helpers
    # -------------------------

    def _store_tx(self, tx_id, direction, source_tx, amount, fee):
        cur = self.db.cursor()
        cur.execute("""
            INSERT INTO transactions
            VALUES (?,?,?,?,?,?,?,?)
        """, (
            tx_id,
            direction,
            source_tx,
            amount,
            fee,
            BridgeStatus.COMPLETED.value,
            self.CONFIRMATION_THRESHOLD,
            int(time.time())
        ))
        self.db.commit()

    def _is_source_processed(self, source_tx):
        cur = self.db.cursor()
        cur.execute("SELECT id FROM transactions WHERE source_tx=?", (source_tx,))
        return cur.fetchone() is not None

    # -------------------------
    # Verification Stubs
    # -------------------------

    def _verify_tron_deposit(self, tx_hash, amount):
        # TODO: Real Tron API verification
        if not tx_hash:
            raise BridgeError("Invalid Tron tx")

    def _verify_erup_burn(self, tx_hash, amount):
        # TODO: Verify burn on ERUP chain
        if not tx_hash:
            raise BridgeError("Invalid ERUP tx")

    # -------------------------
    # State
    # -------------------------

    def get_state(self):
        return {
            "usdt_reserve": self.usdt_reserve,
            "erup_supply": self.erup_supply,
            "invariant_ok": self.erup_supply <= self.usdt_reserve
        }


# =============================
# Run Test
# =============================

if __name__ == "__main__":
    bridge = TronBridge()

    print("=== Mint Test ===")
    print(bridge.mint_from_usdt("tron_tx_1", 10000))

    print("=== Burn Test ===")
    print(bridge.burn_to_usdt("erup_tx_1", 5000))

    print("State:", bridge.get_state())
