"""
deploy.py — Déploiement du smart contract CertiChain sur Polygon Amoy testnet.

Usage:
    python deploy.py

Pré-requis:
    1. Remplir .env avec ADMIN_PRIVATE_KEY (wallet avec du MATIC testnet)
    2. Obtenir du MATIC testnet : https://faucet.polygon.technology/
    3. pip install py-solc-x  (si pas encore installé)

Ce script:
    - Compile automatiquement contracts/CertiChain.sol
    - Déploie sur Polygon Amoy
    - Affiche l'adresse du contrat déployé
    - Met à jour .env avec CONTRACT_ADDRESS automatiquement
"""

import os
import sys
import json
from pathlib import Path
from dotenv import load_dotenv
from web3 import Web3
from web3.middleware import ExtraDataToPOAMiddleware

# ─── Chargement config ────────────────────────────────────────────────────────

load_dotenv()

PRIVATE_KEY    = os.getenv("ADMIN_PRIVATE_KEY", "")
RPC_URL        = os.getenv("POLYGON_RPC_URL", "https://rpc-amoy.polygon.technology")
CHAIN_ID       = int(os.getenv("CHAIN_ID", "80002"))
CONTRACT_PATH  = Path(__file__).parent.parent / "contracts" / "CertiChain.sol"
ENV_FILE       = Path(__file__).parent / ".env"

# ─── Vérifications ────────────────────────────────────────────────────────────

if not PRIVATE_KEY or PRIVATE_KEY == "0xyour_private_key_here":
    print("❌  ADMIN_PRIVATE_KEY non configurée dans .env")
    print("    Renseignez la clé privée de votre wallet de déploiement.")
    sys.exit(1)

if not CONTRACT_PATH.exists():
    print(f"❌  Contrat introuvable : {CONTRACT_PATH}")
    sys.exit(1)

# ─── Compilation du contrat ───────────────────────────────────────────────────

print("📦  Compilation de CertiChain.sol...")

try:
    from solcx import compile_source, install_solc, get_installed_solc_versions

    # Installer solc 0.8.20 si nécessaire
    target_version = "0.8.20"
    installed = [str(v) for v in get_installed_solc_versions()]
    if target_version not in installed:
        print(f"    Installation de solc {target_version}...")
        install_solc(target_version)

    source = CONTRACT_PATH.read_text(encoding="utf-8")

    compiled = compile_source(
        source,
        output_values=["abi", "bin"],
        solc_version=target_version,
        optimize=True,
        optimize_runs=200,
    )

    contract_id   = "<stdin>:CertiChain"
    contract_data = compiled[contract_id]
    ABI           = contract_data["abi"]
    BYTECODE      = contract_data["bin"]

    print(f"    ✅  Compilation réussie ({len(BYTECODE) // 2} bytes)")

except ImportError:
    print("❌  py-solc-x non installé. Exécutez : pip install py-solc-x")
    sys.exit(1)
except Exception as e:
    print(f"❌  Erreur de compilation : {e}")
    sys.exit(1)

# ─── Connexion Polygon Amoy ───────────────────────────────────────────────────

print(f"\n🔗  Connexion à Polygon Amoy ({RPC_URL})...")

w3 = Web3(Web3.HTTPProvider(RPC_URL))
w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)

if not w3.is_connected():
    print("❌  Impossible de se connecter au réseau Polygon Amoy.")
    print("    Vérifiez votre connexion internet ou l'URL RPC dans .env")
    sys.exit(1)

account = w3.eth.account.from_key(PRIVATE_KEY)
balance = w3.eth.get_balance(account.address)
balance_matic = w3.from_wei(balance, "ether")

print(f"    Wallet  : {account.address}")
print(f"    Balance : {balance_matic:.4f} MATIC (testnet)")
print(f"    Réseau  : chain_id={w3.eth.chain_id}")

if balance == 0:
    print("\n⚠️   Balance nulle ! Obtenez du MATIC testnet sur :")
    print("    https://faucet.polygon.technology/")
    print("    (Sélectionnez 'Amoy' et entrez votre adresse)")
    sys.exit(1)

if w3.eth.chain_id != CHAIN_ID:
    print(f"❌  Chain ID attendu {CHAIN_ID}, obtenu {w3.eth.chain_id}")
    sys.exit(1)

# ─── Déploiement ─────────────────────────────────────────────────────────────

print("\n🚀  Déploiement du contrat CertiChain...")

try:
    CertiChainContract = w3.eth.contract(abi=ABI, bytecode=BYTECODE)

    nonce     = w3.eth.get_transaction_count(account.address)
    gas_price = w3.eth.gas_price

    # Estimation du gas pour le déploiement
    deploy_tx = CertiChainContract.constructor().build_transaction({
        "from":     account.address,
        "nonce":    nonce,
        "gasPrice": gas_price,
        "chainId":  CHAIN_ID,
    })

    try:
        estimated_gas    = w3.eth.estimate_gas(deploy_tx)
        deploy_tx["gas"] = int(estimated_gas * 1.2)
    except Exception:
        deploy_tx["gas"] = 2_000_000

    gas_cost_matic = w3.from_wei(deploy_tx["gas"] * gas_price, "ether")
    print(f"    Gas estimé : {deploy_tx['gas']:,} (~{gas_cost_matic:.6f} MATIC)")

    # Signature et envoi
    signed_tx  = account.sign_transaction(deploy_tx)
    tx_hash    = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
    print(f"    TX envoyée : {tx_hash.hex()}")
    print("    Attente de confirmation (peut prendre 15-30 secondes)...")

    receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)

    if receipt["status"] != 1:
        print(f"❌  Transaction échouée (status={receipt['status']})")
        sys.exit(1)

    contract_address = receipt["contractAddress"]

    print(f"\n✅  Contrat déployé avec succès !")
    print(f"    Adresse       : {contract_address}")
    print(f"    Bloc          : {receipt['blockNumber']}")
    print(f"    Gas utilisé   : {receipt['gasUsed']:,}")
    print(f"    TX Hash       : {tx_hash.hex()}")
    print(f"\n    Polygonscan Amoy :")
    print(f"    https://amoy.polygonscan.com/address/{contract_address}")

except Exception as e:
    print(f"❌  Erreur lors du déploiement : {e}")
    sys.exit(1)

# ─── Mise à jour automatique du .env ─────────────────────────────────────────

print("\n📝  Mise à jour de .env...")

try:
    if ENV_FILE.exists():
        content = ENV_FILE.read_text(encoding="utf-8")

        if "CONTRACT_ADDRESS=" in content:
            lines = content.splitlines()
            new_lines = []
            for line in lines:
                if line.startswith("CONTRACT_ADDRESS="):
                    new_lines.append(f"CONTRACT_ADDRESS={contract_address}")
                else:
                    new_lines.append(line)
            ENV_FILE.write_text("\n".join(new_lines) + "\n", encoding="utf-8")
        else:
            with ENV_FILE.open("a", encoding="utf-8") as f:
                f.write(f"\nCONTRACT_ADDRESS={contract_address}\n")

        print(f"    ✅  CONTRACT_ADDRESS mis à jour dans .env")
    else:
        print(f"    ⚠️   .env introuvable — ajoutez manuellement :")
        print(f"    CONTRACT_ADDRESS={contract_address}")

except Exception as e:
    print(f"    ⚠️   Impossible de mettre à jour .env : {e}")
    print(f"    Ajoutez manuellement : CONTRACT_ADDRESS={contract_address}")

# ─── Sauvegarde de l'ABI ─────────────────────────────────────────────────────

abi_path = Path(__file__).parent / "certichain_abi.json"
abi_path.write_text(json.dumps(ABI, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"\n💾  ABI sauvegardé : {abi_path}")

# ─── Résumé final ─────────────────────────────────────────────────────────────

print("\n" + "─" * 60)
print("  DÉPLOIEMENT TERMINÉ")
print("─" * 60)
print(f"  Contract : {contract_address}")
print(f"  Réseau   : Polygon Amoy testnet (chain_id=80002)")
print()
print("  Prochaines étapes :")
print("  1. Vérifiez que CONTRACT_ADDRESS est dans .env")
print("  2. Démarrez le service Python : python run.py")
print("  3. Démarrez le worker Laravel :")
print("     php artisan queue:work --queue=blockchain --timeout=200")
print("─" * 60)
