import os
import sqlite3
import pytest
from fastapi.testclient import TestClient

from app.screener.schema import ensure_screener_schema


@pytest.fixture(autouse=True)
def isolated_db(tmp_path, monkeypatch):
    db_path = tmp_path / "screener_router.db"
    c = sqlite3.connect(db_path)
    ensure_screener_schema(c)
    c.close()
    monkeypatch.setenv("STOCK_DB_PATH", str(db_path))


@pytest.fixture
def client():
    from app.main import app
    return TestClient(app)


def test_get_nodes_lists_8_score_and_1_gate(client):
    r = client.get("/api/stock/screener/nodes")
    assert r.status_code == 200
    body = r.json()
    assert len(body["score_nodes"]) == 8
    assert len(body["gate_nodes"]) == 1
    assert {n["name"] for n in body["score_nodes"]} == {
        "foreign_buy", "volume_surge", "momentum",
        "high52w", "rs_rating", "ma_alignment", "vcp_lite",
        "ai_news",
    }


def test_settings_get_returns_defaults(client):
    r = client.get("/api/stock/screener/settings")
    assert r.status_code == 200
    body = r.json()
    assert body["weights"]["foreign_buy"] == 1.0
    assert body["top_n"] == 20


def test_settings_put_then_get_round_trip(client):
    new_settings = {
        "weights": {"foreign_buy": 2.5, "momentum": 1.0, "volume_surge": 1.0,
                    "high52w": 1.2, "rs_rating": 1.2, "ma_alignment": 1.0, "vcp_lite": 0.8},
        "node_params": {"foreign_buy": {"window_days": 7}},
        "gate_params": {"min_market_cap_won": 100_000_000_000,
                        "min_avg_value_won": 500_000_000,
                        "min_listed_days": 60,
                        "skip_managed": True, "skip_preferred": True, "skip_spac": True,
                        "skip_halted_days": 3},
        "top_n": 30,
        "rr_ratio": 2.5,
        "atr_window": 14,
        "atr_stop_mult": 2.0,
    }
    r = client.put("/api/stock/screener/settings", json=new_settings)
    assert r.status_code == 200
    r2 = client.get("/api/stock/screener/settings")
    body = r2.json()
    assert body["weights"]["foreign_buy"] == 2.5
    assert body["top_n"] == 30


# ---- /run tests ----

from app.screener._test_fixtures import make_master, make_prices, make_flow


def _seed_min(conn, asof_iso="2026-05-12"):
    import datetime as dt
    now = dt.datetime.utcnow().isoformat()
    rows = [
        ("BIG1", "큰주식1", "KOSPI", 200_000_000_000, 0, 0, 0, None, now),
        ("BIG2", "큰주식2", "KOSPI", 100_000_000_000, 0, 0, 0, None, now),
        ("SMALL", "작은주식", "KOSPI", 1_000_000_000, 0, 0, 0, None, now),
    ]
    for r in rows:
        conn.execute("""INSERT INTO krx_master (ticker,name,market,market_cap,
                       is_managed,is_preferred,is_spac,listed_date,updated_at)
                       VALUES (?,?,?,?,?,?,?,?,?)""", r)
    asof = dt.date(2026, 5, 12)
    p = make_prices(["BIG1", "BIG2", "SMALL"], days=260, asof=asof)
    f = make_flow(["BIG1", "BIG2", "SMALL"], days=260, asof=asof,
                  foreign_per_day={"BIG1": 100_000_000, "BIG2": 50_000_000, "SMALL": 0})
    p.to_sql("krx_daily_prices", conn, if_exists="append", index=False)
    f.to_sql("krx_flow", conn, if_exists="append", index=False)
    conn.commit()


def test_run_preview_no_save(client):
    db_path = os.environ["STOCK_DB_PATH"]
    c = sqlite3.connect(db_path)
    _seed_min(c)
    c.close()

    r = client.post("/api/stock/screener/run", json={"mode": "preview", "asof": "2026-05-12"})
    assert r.status_code == 200
    body = r.json()
    assert body["status"] == "success"
    assert body["run_id"] is None
    assert body["telegram_payload"] is not None

    c = sqlite3.connect(db_path)
    cnt = c.execute("SELECT count(*) FROM screener_runs").fetchone()[0]
    assert cnt == 0


def test_run_manual_save_writes_row(client):
    db_path = os.environ["STOCK_DB_PATH"]
    c = sqlite3.connect(db_path)
    _seed_min(c)
    c.close()

    r = client.post("/api/stock/screener/run",
                    json={"mode": "manual_save", "asof": "2026-05-12"})
    assert r.status_code == 200
    assert r.json()["run_id"] is not None

    c = sqlite3.connect(db_path)
    cnt = c.execute("SELECT count(*) FROM screener_runs").fetchone()[0]
    assert cnt == 1


def test_runs_list_and_detail(client):
    db_path = os.environ["STOCK_DB_PATH"]
    c = sqlite3.connect(db_path)
    _seed_min(c)
    c.close()

    saved = client.post(
        "/api/stock/screener/run",
        json={"mode": "manual_save", "asof": "2026-05-12"},
    ).json()
    run_id = saved["run_id"]

    list_r = client.get("/api/stock/screener/runs?limit=5")
    assert list_r.status_code == 200
    assert any(r["id"] == run_id for r in list_r.json())

    detail = client.get(f"/api/stock/screener/runs/{run_id}")
    assert detail.status_code == 200
    assert detail.json()["meta"]["id"] == run_id
    assert isinstance(detail.json()["results"], list)


def test_run_holiday_returns_skipped(client):
    # 2026-05-09는 토요일 (주말). _is_holiday 가 weekday>=5를 잡음.
    r = client.post("/api/stock/screener/run",
                    json={"mode": "auto", "asof": "2026-05-09"})
    assert r.status_code == 200
    assert r.json()["status"] == "skipped_holiday"
