import tempfile

import pytest

from strategy_engine import StrategyEngine

try:
    import flask  # noqa: F401
    import app as web_app
except ModuleNotFoundError:
    web_app = None


def make_engine(state_dir, symbol, index_name):
    return StrategyEngine(
        "id",
        "secret",
        testnet=True,
        state_dir=state_dir,
        config={
            "instrument_name": symbol,
            "index_name": index_name,
            "allocation_usdc": 250,
            "trade_size_usdc": 25,
        },
    )


def test_instances_use_separate_state_files():
    with tempfile.TemporaryDirectory() as state_dir:
        btc = make_engine(state_dir, "BTC_USDC", "btc_usdc")
        eth = make_engine(state_dir, "ETH_USDC", "eth_usdc")

        assert btc.state_file != eth.state_file
        assert btc.state_file.endswith("state_btcusdc.json")
        assert eth.state_file.endswith("state_ethusdc.json")
        assert btc.cfg["trade_size_usdc"] == eth.cfg["trade_size_usdc"] == 25


def test_virtual_balances_never_expose_testnet_faucet_balance():
    with tempfile.TemporaryDirectory() as state_dir:
        engine = make_engine(state_dir, "BTC_USDC", "btc_usdc")
        engine.btc_index_price = 50_000
        engine.initial_usdc = 125
        engine.initial_btc = 0.0025
        engine.initial_total_usdc = 250
        engine.account_usdc_balance = 100_000
        engine.account_btc_balance = 10

        engine._apply_virtual_balances()

        assert engine.usdc_balance == 125
        assert engine.btc_balance == 0.0025
        assert engine.total_value_usdc == 250

        engine.trades = [
            {
                "side": "buy",
                "amount_btc": 0.0005,
                "price": 50_000,
                "total_usdc": 25,
            }
        ]
        engine._apply_virtual_balances()

        assert engine.usdc_balance == 100
        assert engine.btc_balance == 0.003
        assert engine.total_value_usdc == 250


def test_web_exposes_both_symbols_without_creating_engines():
    if web_app is None:
        pytest.skip("Flask is not installed in the host test environment")
    web_app.engines.clear()
    client = web_app.app.test_client()

    response = client.get("/api/symbols")
    assert response.status_code == 200
    payload = response.get_json()
    assert [item["symbol"] for item in payload["symbols"]] == [
        "BTC_USDC",
        "ETH_USDC",
    ]
    assert payload["total_capital_usdc"] == 500

    eth_status = client.get("/api/status?symbol=ETH_USDC")
    assert eth_status.status_code == 200
    assert eth_status.get_json()["symbol"] == "ETH_USDC"
    assert web_app.engines == {}


def test_web_engines_share_one_rest_auth_client():
    if web_app is None:
        pytest.skip("Flask is not installed in the host test environment")
    web_app.engines.clear()
    web_app.shared_api_clients.clear()

    btc = web_app._get_or_create_engine("BTC_USDC")
    eth = web_app._get_or_create_engine("ETH_USDC")

    assert btc.api is eth.api
    assert len(web_app.shared_api_clients) == 1


def test_start_rejects_engine_before_initialization_finishes():
    with tempfile.TemporaryDirectory() as state_dir:
        engine = make_engine(state_dir, "BTC_USDC", "btc_usdc")
        engine._running = True
        engine.status = "initializing"

        assert engine.start() is False
        assert engine._trading_enabled is False


def test_order_amount_rounds_down_to_stay_inside_budget():
    with tempfile.TemporaryDirectory() as state_dir:
        engine = make_engine(state_dir, "BTC_USDC", "btc_usdc")
        engine.contract_size = 0.0001

        assert engine._round_amount(0.00019) == 0.0001
        assert engine._round_amount(0.00009) == 0


def test_ready_engine_enters_running_state_immediately():
    with tempfile.TemporaryDirectory() as state_dir:
        engine = make_engine(state_dir, "BTC_USDC", "btc_usdc")
        engine._running = True
        engine.status = "ready"
        engine._save_state = lambda: None

        assert engine.start() is True
        assert engine.status == "running"
        assert engine._trading_enabled is True
