"""sim CLI.

  python3 -m sim scan [--force]   # 1회 스캔 (launchd/cron 진입점)
  python3 -m sim status           # 가상계좌 요약
  python3 -m sim report [N]       # 최근 거래 N건 (기본 20)
  python3 -m sim reset [--yes]    # 가상계좌 초기화
  python3 -m sim variants sync    # 비교군을 백테스트 유형별 1위로 동기화 (수동 전용)
"""
from __future__ import annotations

import json
import sys

from . import config, engine
from .portfolio import Portfolio


def _cmd_scan(argv):
    snap = engine.scan_all(force='--force' in argv)
    if snap.get('skipped'):
        print(f"[skip] {snap['reason']} @ {snap['at']}")
        return
    s = snap['summary']
    print(f"자산 {s['equity']:,}원 ({s['total_return_pct']:+.2f}%) · 현금 {s['cash']:,} · "
          f"보유 {s['open_positions']} · 매수 {snap['counts']['buys']} 매도 {snap['counts']['sells']}")


def _cmd_status(argv):
    pf = Portfolio.load()
    s = pf.summary()
    print(f"가상계좌 (초기 {s['initial']:,}원)")
    print(f"  평가자산 {s['equity']:,}원  ({s['total_return_pct']:+.2f}%)")
    print(f"  현금 {s['cash']:,} · 주식 {s['held_value']:,}")
    print(f"  실현손익 {s['realized_pnl']:,} · 청산 {s['closed_trades']}건 "
          f"승률 {s['win_rate_pct']}% · MDD {s['max_drawdown_pct']}%")
    if pf.positions:
        print('  보유:')
        for p in pf.positions.values():
            cur = p.get('cur_price', p['entry_price'])
            pnl = (cur / p['entry_price'] - 1) * 100
            tr = ' [트레일링]' if p.get('trailing_on') else ''
            print(f"    {p['name']:16s} {p['qty']}주 @{p['entry_price']:,} → {cur:,} "
                  f"({pnl:+.1f}%) 손절 {p['stop']:,} 목표 {p['target']:,}{tr}")


def _cmd_report(argv):
    n = next((int(a) for a in argv if a.isdigit()), 20)
    if not config.TRADES_PATH.exists():
        print('거래 없음')
        return
    lines = config.TRADES_PATH.read_text().splitlines()[-n:]
    for line in lines:
        r = json.loads(line)
        if r['side'] == 'BUY':
            print(f"{r['ts'][:16]} 매수 {r['name']:16s} {r['qty']}주 @{r['price']:,} · {r['reason']}")
        else:
            print(f"{r['ts'][:16]} 매도 {r['name']:16s} {r['qty']}주 @{r['price']:,} "
                  f"손익 {r['pnl']:,}({r['pnl_pct']:+.1f}%) · {r['reason']}")


def _cmd_sweep(argv):
    from . import sweep
    frac = next((float(a) for a in argv if a.replace('.', '').isdigit()), 0.7)
    res = sweep.run_sweep(train_frac=frac)
    if res.get('error'):
        print('스윕 실패:', res)
        return
    print(f"스윕 완료 — {res['count']}개 조합 · 검증 {res['split']['test']} "
          f"· 수급반영 {res['flow_used']}")
    for r in res['results'][:10]:
        p, te = r['params'], r['test']
        print(f"  RR{p['RR_RATIO']} S{p['STOP_ATR_MULT']} SMA{p['SMA_LONG']} P{p['PULLBACK_ATR_MULT']} → "
              f"검증 {te['total_return_pct']:+}% MDD {te['mdd_pct']}% 거래 {te['trades']} 승률 {te['win_rate_pct']}%")


def _cmd_backfill(argv):
    from . import backfill_flow
    pages = int(argv[argv.index('--pages') + 1]) if '--pages' in argv else backfill_flow.DEFAULT_PAGES
    res = backfill_flow.backfill(pages=pages, force='--force' in argv)
    print(f"수급 백필 — 신규 {res['fetched']} · 스킵 {res['skipped']} · 실패 {res['failed']} "
          f"· DB {res['codes_in_db']}종목 {res['total_rows']}행")


def _cmd_backtest(argv):
    from . import backtest, universe
    codes = [e['code'] for e in universe.build_universe()]
    import json
    print(json.dumps(backtest.run(None, codes), ensure_ascii=False, indent=2))


def _cmd_backfill_index(argv):
    from . import benchmark
    pages = int(argv[argv.index('--pages') + 1]) if '--pages' in argv else 8
    res = benchmark.backfill(pages=pages)
    print(f"지수 백필 — 신규 {res}")
    for idx in benchmark.INDICES:
        ks = sorted(benchmark.series(idx))
        if ks:
            print(f"  {idx}: {ks[0]} ~ {ks[-1]} ({len(ks)}일)")


def _cmd_variants(argv):
    from . import variants
    sub = argv[0] if argv else 'list'
    if sub == 'seed':
        n = next((int(a) for a in argv[1:] if a.isdigit()), 3)
        vs = variants.seed_from_sweep(n)
        print(f'변이 {len(vs)}개 등록:')
        for v in vs:
            print(' ', v['id'], v['name'])
    elif sub == 'sync':
        import json as _json
        from . import config as _cfg
        res = _json.loads((_cfg.STATE_DIR / 'backtest_results.json').read_text())
        print('동기화:', variants.sync_label_tops(res))
    elif sub == 'reset':
        variants.reset_all()
        print('변이 계좌 초기화 (정의 유지)')
    elif sub == 'clear':
        variants.clear()
        print('변이 정의·계좌 전부 삭제')
    elif sub == 'philosophy':
        res = variants.add_philosophy_presets()
        print(f"철학별 전략 추가: 신규 {len(res['added'])}개 · 중복 {res['skipped']}개 · 총 {res['total']}개")
        for v in res['added']:
            print(' ', v['id'], v['name'])
    else:
        vs = variants.load_variants()
        print(f'변이 {len(vs)}개:')
        for v in vs:
            print(' ', v['id'], v['name'], v['params'])


def _cmd_reset(argv):
    if '--yes' not in argv:
        print('정말 초기화하려면 --yes 를 붙이세요 (가상계좌·거래·스냅샷 삭제)')
        return
    for p in (config.PORTFOLIO_PATH, config.TRADES_PATH, config.LAST_SCAN_PATH):
        if p.exists():
            p.unlink()
    print(f'초기화 완료 — 가상자본 {config.INITIAL_CAPITAL:,}원')


def _cmd_universe(argv):
    """관찰목록 자동편입/제외 — 매일 장 마감 후 1회. 'import'=주도주 편입, 'prune'=무신호 auto 제외, 둘 다 기본."""
    from . import universe
    sub = argv[0] if argv else 'all'
    if sub in ('import', 'all'):
        print('자동편입:', universe.auto_import())
    if sub in ('prune', 'all'):
        print('자동제외:', universe.auto_prune())


def main():
    argv = sys.argv[1:]
    cmd = argv[0] if argv else 'status'
    rest = argv[1:]
    {'scan': _cmd_scan, 'status': _cmd_status, 'report': _cmd_report,
     'sweep': _cmd_sweep, 'backtest': _cmd_backtest, 'backfill': _cmd_backfill,
     'backfill-index': _cmd_backfill_index, 'universe': _cmd_universe,
     'variants': _cmd_variants, 'reset': _cmd_reset}.get(cmd, lambda a: print(__doc__))(rest)


if __name__ == '__main__':
    main()
