#!/usr/bin/env python3
"""
Automated Ethereum Mainnet Contract Verification Script
Handles Standard JSON Input verification via Etherscan API
"""

import json
import sys
import time
import urllib.parse
import urllib.request
from pathlib import Path

# Colors for terminal output
class Colors:
    RED = '\033[0;31m'
    GREEN = '\033[0;32m'
    YELLOW = '\033[1;33m'
    BLUE = '\033[0;34m'
    CYAN = '\033[0;36m'
    NC = '\033[0m'  # No Color

def log_info(msg):
    print(f"{Colors.BLUE}[INFO]{Colors.NC} {msg}")

def log_success(msg):
    print(f"{Colors.GREEN}[✓]{Colors.NC} {msg}")

def log_warn(msg):
    print(f"{Colors.YELLOW}[⚠]{Colors.NC} {msg}")

def log_error(msg):
    print(f"{Colors.RED}[✗]{Colors.NC} {msg}")

def log_step(msg):
    print(f"{Colors.CYAN}[STEP]{Colors.NC} {msg}")

# Contract configuration
CONTRACTS = {
    "0x89dd12025bfCD38A168455A44B400e913ED33BE2": {
        "name": "CCIPWETH9Bridge",
        "constructor_args": "0x00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca",
        "standard_json_file": "docs/CCIPWETH9Bridge_standard_json.json"
    }
}

def load_env_file(env_path):
    """Load environment variables from .env file"""
    env_vars = {}
    try:
        with open(env_path, 'r') as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#') and '=' in line:
                    key, value = line.split('=', 1)
                    env_vars[key.strip()] = value.strip().strip('"').strip("'")
    except FileNotFoundError:
        log_error(f".env file not found: {env_path}")
        sys.exit(1)
    return env_vars

def check_verification_status(address, api_key):
    """Check if contract is already verified on Etherscan"""
    url = f"https://api.etherscan.io/api?module=contract&action=getsourcecode&address={address}&apikey={api_key}"
    
    try:
        with urllib.request.urlopen(url) as response:
            data = json.loads(response.read().decode())
            
            if data.get('status') == '1' and data.get('result'):
                result = data['result'][0]
                source_code = result.get('SourceCode', '')
                
                # Check if source code exists (verified)
                if source_code and source_code not in ['', '{{']:
                    return True
            return False
    except Exception as e:
        log_warn(f"Could not check verification status: {e}")
        return False

def verify_contract(address, contract_info, api_key):
    """Verify contract using Standard JSON Input via Etherscan API"""
    contract_name = contract_info['name']
    constructor_args = contract_info['constructor_args']
    standard_json_file = contract_info['standard_json_file']
    
    # Load Standard JSON file
    project_root = Path(__file__).parent.parent
    json_path = project_root / standard_json_file
    
    if not json_path.exists():
        log_error(f"Standard JSON file not found: {json_path}")
        return False
    
    log_step(f"Loading Standard JSON from {json_path}")
    try:
        with open(json_path, 'r') as f:
            standard_json = json.load(f)
    except Exception as e:
        log_error(f"Failed to load Standard JSON: {e}")
        return False
    
    # Convert to compact JSON string
    json_str = json.dumps(standard_json, separators=(',', ':'))
    
    # Prepare API request
    api_url = "https://api.etherscan.io/api"
    
    params = {
        'module': 'contract',
        'action': 'verifysourcecode',
        'apikey': api_key,
        'contractaddress': address,
        'codeformat': 'solidity-standard-json-input',
        'contractname': contract_name,
        'compilerversion': 'v0.8.20+commit.a1b79de6',
        'optimizationUsed': '1',
        'runs': '200',
        'constructorArguements': constructor_args,
        'sourceCode': json_str
    }
    
    # Encode parameters
    data = urllib.parse.urlencode(params).encode('utf-8')
    
    log_step("Submitting verification request to Etherscan...")
    try:
        req = urllib.request.Request(api_url, data=data)
        with urllib.request.urlopen(req, timeout=30) as response:
            result = json.loads(response.read().decode())
            
            if result.get('status') == '1':
                guid = result.get('result', '')
                if guid and guid != 'null':
                    log_success(f"Verification submitted successfully!")
                    log_info(f"GUID: {guid}")
                    log_info(f"Check status: https://etherscan.io/address/{address}#code")
                    return True
                else:
                    log_error(f"Verification failed: {result.get('result', 'Unknown error')}")
                    return False
            else:
                error_msg = result.get('result', 'Unknown error')
                log_error(f"Verification failed: {error_msg}")
                return False
    except urllib.error.HTTPError as e:
        log_error(f"HTTP Error: {e}")
        try:
            error_body = e.read().decode()
            log_info(f"Error details: {error_body}")
        except:
            pass
        return False
    except Exception as e:
        log_error(f"Request failed: {e}")
        return False

def monitor_verification(address, api_key, max_attempts=12):
    """Monitor verification status after submission"""
    log_info("Waiting for verification to complete...")
    
    for attempt in range(1, max_attempts + 1):
        time.sleep(5)
        
        if check_verification_status(address, api_key):
            log_success("Contract is now verified!")
            return True
        
        log_info(f"Attempt {attempt}/{max_attempts}: Still processing...")
    
    log_warn("Verification may still be processing. Check Etherscan manually.")
    return False

def main():
    log_info("=" * 50)
    log_info("Ethereum Mainnet Contract Verification")
    log_info("Using Standard JSON Input Method")
    log_info("=" * 50)
    log_info("")
    
    # Load environment variables
    project_root = Path(__file__).parent.parent
    source_project = project_root.parent / "smom-dbis-138"
    env_path = source_project / ".env"
    
    if not env_path.exists():
        log_error(f".env file not found: {env_path}")
        sys.exit(1)
    
    env_vars = load_env_file(env_path)
    
    api_key = env_vars.get('ETHERSCAN_API_KEY')
    if not api_key:
        log_error("ETHERSCAN_API_KEY not found in .env file")
        sys.exit(1)
    
    # Process each contract
    verified_count = 0
    already_verified_count = 0
    failed_count = 0
    
    for address, contract_info in CONTRACTS.items():
        log_info("")
        log_info("=" * 50)
        log_info(f"Verifying: {contract_info['name']}")
        log_info(f"Address: {address}")
        log_info("=" * 50)
        log_info("")
        
        # Check if already verified
        log_step("Checking current verification status...")
        if check_verification_status(address, api_key):
            log_success("Contract is already verified on Etherscan!")
            log_info(f"View contract: https://etherscan.io/address/{address}#code")
            already_verified_count += 1
            continue
        
        log_info("Contract is not yet verified")
        
        # Verify contract
        log_step("Submitting verification request...")
        if verify_contract(address, contract_info, api_key):
            log_info("")
            log_step("Monitoring verification status...")
            if monitor_verification(address, api_key):
                verified_count += 1
            else:
                log_warn("Verification submitted but status unclear. Check Etherscan manually.")
        else:
            failed_count += 1
            log_info("")
            log_info("Manual verification steps:")
            log_info(f"1. Go to: https://etherscan.io/address/{address}#code")
            log_info("2. Click 'Contract' tab → 'Verify and Publish'")
            log_info("3. Select 'Standard JSON Input'")
            log_info(f"4. Upload: {project_root / contract_info['standard_json_file']}")
            log_info(f"5. Enter constructor args: {contract_info['constructor_args']}")
            log_info("6. Submit")
    
    # Summary
    log_info("")
    log_info("=" * 50)
    log_info("Verification Summary")
    log_info("=" * 50)
    log_info("")
    log_success(f"Already Verified: {already_verified_count}")
    log_success(f"Newly Verified: {verified_count}")
    log_error(f"Failed: {failed_count}")
    log_info("")
    
    total = already_verified_count + verified_count + failed_count
    log_info(f"Total Contracts: {total}")
    
    if failed_count == 0:
        log_success("All contracts processed successfully!")
    else:
        log_warn("Some contracts require manual verification.")

if __name__ == "__main__":
    main()

