import pytest
from fxhnt.application.fund_config import (
    FundConfig, read_fund_config, write_fund_config, seed_fund_config,
)
from fxhnt.adapters.persistence.cockpit_models import CockpitBase, FundConfigRow
from sqlalchemy import create_engine
from sqlalchemy.pool import StaticPool

def _dsn():
    return "sqlite://"

def _fresh_engine_dsn():
    # a dsn whose table has NOT been created yet (fallback path)
    return "sqlite://"

def test_read_fallback_when_table_absent(monkeypatch):
    # No migrate() called → table absent → settings/policy defaults
    from fxhnt.application.allocation_policy import AllocationPolicy
    from fxhnt.config import get_settings
    cfg = read_fund_config("sqlite://")
    assert cfg.capital == get_settings().paper_capital
    assert cfg.target_vol == AllocationPolicy().target_vol
    assert cfg.kelly_fraction == AllocationPolicy().kelly_fraction
    assert cfg.max_venue_weight == 1.0


def test_max_venue_weight_default_and_roundtrip():
    import os
    p = "./.pytest_fc_venue.db"
    if os.path.exists(p): os.remove(p)
    seed_fund_config(f"sqlite:///{p}")
    assert read_fund_config(f"sqlite:///{p}").max_venue_weight == 1.0
    write_fund_config(f"sqlite:///{p}", max_venue_weight=0.6)
    cfg = read_fund_config(f"sqlite:///{p}")
    assert cfg.max_venue_weight == 0.6 and cfg.target_vol == 0.20   # partial-override: vol unchanged
    os.remove(p)


def test_max_venue_weight_validation():
    p = "./.pytest_fc_venue_val.db"
    import os
    if os.path.exists(p): os.remove(p)
    for bad in (0.0, -0.1, 1.5):
        with pytest.raises(ValueError):
            write_fund_config(f"sqlite:///{p}", max_venue_weight=bad)
    if os.path.exists(p): os.remove(p)

def test_write_then_read_roundtrip():
    dsn = "sqlite:///./.pytest_fund_cfg_rt.db"
    import os
    if os.path.exists("./.pytest_fund_cfg_rt.db"): os.remove("./.pytest_fund_cfg_rt.db")
    write_fund_config(dsn, capital=250_000.0, target_vol=0.20, kelly_fraction=0.5)
    cfg = read_fund_config(dsn)
    assert (cfg.capital, cfg.target_vol, cfg.kelly_fraction) == (250_000.0, 0.20, 0.5)
    os.remove("./.pytest_fund_cfg_rt.db")

def test_partial_override_leaves_other_fields():
    dsn = "sqlite:///./.pytest_fund_cfg_po.db"
    import os
    if os.path.exists("./.pytest_fund_cfg_po.db"): os.remove("./.pytest_fund_cfg_po.db")
    write_fund_config(dsn, capital=100_000.0, target_vol=0.20, kelly_fraction=0.5)
    write_fund_config(dsn, capital=300_000.0)          # only capital
    cfg = read_fund_config(dsn)
    assert cfg.capital == 300_000.0
    assert cfg.target_vol == 0.20                       # unchanged
    assert cfg.kelly_fraction == 0.5                    # unchanged
    os.remove("./.pytest_fund_cfg_po.db")

@pytest.mark.parametrize("kw", [
    {"capital": 0.0}, {"capital": -5.0},
    {"target_vol": 0.0}, {"target_vol": 1.5},
    {"kelly_fraction": 0.0}, {"kelly_fraction": 2.0},
])
def test_validation_rejects(kw):
    dsn = "sqlite:///./.pytest_fund_cfg_val.db"
    import os
    if os.path.exists("./.pytest_fund_cfg_val.db"): os.remove("./.pytest_fund_cfg_val.db")
    with pytest.raises(ValueError):
        write_fund_config(dsn, **kw)
    if os.path.exists("./.pytest_fund_cfg_val.db"): os.remove("./.pytest_fund_cfg_val.db")

def test_seed_is_insert_if_absent():
    dsn = "sqlite:///./.pytest_fund_cfg_seed.db"
    import os
    if os.path.exists("./.pytest_fund_cfg_seed.db"): os.remove("./.pytest_fund_cfg_seed.db")
    seed_fund_config(dsn)
    assert read_fund_config(dsn) == FundConfig(100_000.0, 0.20, 0.5, 1.0)
    write_fund_config(dsn, capital=500_000.0)
    seed_fund_config(dsn)                                # must NOT clobber
    assert read_fund_config(dsn).capital == 500_000.0
    os.remove("./.pytest_fund_cfg_seed.db")
