import json
import subprocess
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]


def run_php(source: str):
    completed = subprocess.run(
        ["php", "-r", source],
        cwd=ROOT,
        capture_output=True,
        text=True,
    )
    assert completed.returncode == 0, completed.stderr
    return json.loads(completed.stdout)


def test_private_start_preserves_linear_quote_baseline_and_keeps_inverse_conversion():
    source = (ROOT / "api" / "private" / "start.php").read_text(encoding="utf-8")

    assert "$instrument_data = $instrument->get($test_data['instrument_id']);" in source
    assert "$test_data['is_linear'] = (int)($instrument_data['is_linear'] ?? 0);" in source
    assert "$starting_equity_in_currency = $test_data['is_linear'] == 1" in source

    fixtures = [(1, 1000, 100), (0, 1000, 100)]
    expected = [1000, 10]
    actual = [
        amount if is_linear == 1 else amount / close
        for is_linear, amount, close in fixtures
    ]
    assert actual == expected


def test_calc_final_amount_uses_quote_equity_for_linear_and_price_conversion_for_inverse():
    source = """
    class ErrorHandlerBee {
        public static function catchNull($value) { return $value; }
        public static function isTrue($value) {
            if (!$value) throw new RuntimeException('redis write failed');
            return $value;
        }
    }
    require %s;
    class SettlementRedis {
        public array $values = [];
        public function jsonget($key) { return json_encode($this->values[$key] ?? null); }
        public function jsonset($key, $path, $value) {
            $field = ltrim($path, '$.');
            $this->values[$key][$field] = $value;
            return true;
        }
        public function disconnect() {}
    }
    $redis = new SettlementRedis();
    $redis->values['test:1'] = ['equity' => 10, 'mark_price' => 100, 'is_linear' => 1];
    $reflection = new ReflectionClass(Test::class);
    $test = $reflection->newInstanceWithoutConstructor();
    foreach ([['redis', $redis], ['test_id', 1]] as [$name, $value]) {
        $property = new ReflectionProperty(Test::class, $name);
        $property->setAccessible(true);
        $property->setValue($test, $value);
    }
    $test->CalcFinalAmount();
    $linear = $redis->values['test:1']['final_amount'];

    $redis->values['test:1'] = ['equity' => 10, 'mark_price' => 100, 'is_linear' => 0];
    $test->CalcFinalAmount();
    echo json_encode([$linear, $redis->values['test:1']['final_amount']]);
    """ % json.dumps(str(ROOT / "classes" / "Test.php"))

    assert run_php(source) == [10, 1000]


def test_private_test_data_output_uses_canonical_linear_quote_and_inverse_base_currency():
    source = (ROOT / "api" / "private" / "get_test_data.php").read_text(
        encoding="utf-8"
    )

    assert "Instrument::getSettlementCurrency($instrument_data)" in source

    def settlement_currency(instrument):
        return instrument["quote_currency"] if instrument["is_linear"] else instrument["base_currency"]

    assert settlement_currency(
        {"is_linear": 1, "base_currency": "BTC", "quote_currency": "USDT"}
    ) == "USDT"
    assert settlement_currency(
        {"is_linear": 0, "base_currency": "BTC", "quote_currency": "USD"}
    ) == "BTC"
