
import os
import sys
import time
import traceback
import pythonnet
from pythonnet import load
import clr
import System
from System.CodeDom.Compiler import CodeDomProvider, CompilerParameters

# --- Configuration to Test ---
SERVERS = [
    "ritpz01000.01.rithmic.com:56000",
    "ritpz01000.01.rithmic.com:65000",
    "ritpz05001.rithmic.com:56000",
    "ritpz05001.rithmic.com:65000",
    "rithmic.com:80",
    "paper.rithmic.com:80",
]

ENV_KEYS = [
    "rithmic_paper_prod_domain", # From omneconfig.tbl
    "Rithmic Paper Trading",     # Common Human Readable Name
    "Rithmic Test",
    "Rithmic 01",
    "rithmic_paper_aws_jp_domain",
    "rithmic_paper_aws_us_domain",
    "rithmic_paper_aws_eu_domain",
    "Rithmic Paper",
    "Paper Trading",
    "Simulated Trading",
]

# --- Setup Pythonnet ---
libs_dir = os.path.join(os.getcwd(), "libs")
if not os.path.exists(libs_dir):
    libs_dir = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), "libs")

sys.path.append(libs_dir)
if hasattr(os, "add_dll_directory"):
    os.add_dll_directory(libs_dir)

dll_path = os.path.join(libs_dir, "rapiplus.dll")
clr.AddReference("rapiplus")
import com.omnesys.rapi as rapi

# --- C# Wrapper Compilation ---
def compile_wrapper():
    csharp_code = """
    using System;
    using com.omnesys.rapi;

    namespace RithmicBridge.TestWrapper
    {
        public class TestAdmCallbacks : AdmCallbacks
        {
            public Action<AlertInfo> OnAlert;
            public Action<EnvironmentInfo> OnEnvironment;

            public override void Alert(AlertInfo oInfo) { if (OnAlert != null) OnAlert(oInfo); }
            public override void EnvironmentList(EnvironmentListInfo oInfo) {}
            public override void Environment(EnvironmentInfo oInfo) { if (OnEnvironment != null) OnEnvironment(oInfo); }

            public override bool Equals(object obj) { return base.Equals(obj); }
            public override int GetHashCode() { return base.GetHashCode(); }
            public override string ToString() { return base.ToString(); }
        }

        public class TestRCallbacks : RCallbacks
        {
            public override void Dbo(DboInfo oInfo) {}
            public override void TradePrint(TradeInfo oInfo) {}
            public override bool Equals(object obj) { return base.Equals(obj); }
            public override int GetHashCode() { return base.GetHashCode(); }
            public override string ToString() { return base.ToString(); }
        }
    }
    """
    provider = CodeDomProvider.CreateProvider("CSharp")
    params = CompilerParameters()
    params.GenerateInMemory = True
    params.ReferencedAssemblies.Add("System.dll")
    params.ReferencedAssemblies.Add(dll_path)
    
    results = provider.CompileAssemblyFromSource(params, csharp_code)
    if results.Errors.HasErrors:
        print("Compilation Errors:")
        for error in results.Errors:
            print(f"  {error.ErrorText}")
        return None
    return results.CompiledAssembly

# --- Test Logic ---
def test_connection(server, env_key, user, password, wrapper_assembly):
    print(f"Testing [Server: {server}, Env: {env_key}] ...")
    
    t_adm = wrapper_assembly.GetType("RithmicBridge.TestWrapper.TestAdmCallbacks")
    t_r = wrapper_assembly.GetType("RithmicBridge.TestWrapper.TestRCallbacks")
    t_alert_info = rapi.AlertInfo
    t_env_info = rapi.EnvironmentInfo

    adm_cb = System.Activator.CreateInstance(t_adm)
    r_cb = System.Activator.CreateInstance(t_r)

    # Callbacks
    def _on_alert(info):
        print(f"  [ALERT] {info.Message} (Id: {info.AlertId})")
    
    def _on_environment(info):
        print(f"  [ENV FOUND] {info.EnvKey} - {info.Description}")

    adm_cb.OnAlert = System.Action[t_alert_info](_on_alert)
    adm_cb.OnEnvironment = System.Action[t_env_info](_on_environment)

    # Params
    params = rapi.REngineParams()
    params.AppName = "TestConnect"
    params.AppVersion = "1.0.0"
    params.AdmCallbacks = adm_cb
    params.LogFilePath = os.path.abspath(f"test_rapi_{server.replace(':', '_')}.log")
    params.DmnSrvrAddr = server
    params.DomainName = env_key # Usually irrelevant for initialization but good to set
    params.LicSrvrAddr = server # Try using same server for all
    params.LocBrokAddr = server
    params.LoggerAddr = server

    engine = None
    try:
        engine = rapi.REngine(params)
        print("  -> REngine Instantiation: SUCCESS")
    except Exception as e:
        print(f"  -> REngine Instantiation: FAILED ({e})")
        return # Cannot proceed

    # Wait for env callbacks
    print("  Waiting 3s for Env callbacks...")
    time.sleep(3)

    # Login
    try:
        engine.login(
            r_cb,
            env_key, user, password, server,
            env_key, user, password, server,
            server,
            env_key, user, password, server
        )
        print("  -> Login Command Sent: SUCCESS")
    except Exception as e:
        print(f"  -> Login Command Sent: FAILED ({e})")

    # Wait for login result
    print("  Waiting 3s for Login result...")
    time.sleep(3)
    
    # Shutdown
    try:
        engine.shutdown()
    except:
        pass
    print("-" * 40)

def main():
    # Load credentials from env or hardcode for testing if needed (but prefer env)
    # Using dotenv to load .env manually if needed, or assume environment is set
    try:
        from dotenv import load_dotenv
        load_dotenv()
    except:
        pass

    user = os.environ.get("RITHMIC_USER")
    password = os.environ.get("RITHMIC_PASSWORD")
    
    if not user or not password:
        print("Error: RITHMIC_USER and RITHMIC_PASSWORD must be set in .env")
        return

    assembly = compile_wrapper()
    if not assembly:
        return

    for server in SERVERS:
        print(f"=== Testing Server: {server} ===")
        # サーバーごとにアセンブリを使い回して、複数のEnvKeyをテストする
        # ただしREngineは再利用できない可能性があるため、テストごとに関数を呼び出す形にする
        # ここでは代表的なEnvKeyをいくつか試す
        
        # まずはサーバー接続確認のために1つ試す
        # インスタンス化だけ成功すれば、あとはLoginでEnvKeyを変えて試行できるか？
        # REngine.login() は失敗すると例外を投げるが、Engine自体が壊れるわけではない？
        # しかし安全のため、毎回初期化する
        
        for env_key in ENV_KEYS:
            test_connection(server, env_key, user, password, assembly)
            # 少し休憩
            time.sleep(1)

if __name__ == "__main__":
    main()
