"""
AkDevz AI Market Intelligence — Enterprise Integration & Security Test Suite
Validates:
1. Broker Failover and Single Execution Broker Guarantee
2. Idempotency Key & Duplicate Order Prevention
3. Risk Gates & Emergency Kill Switch Enforcement
4. News Intelligence Entity Mapping & Sentiment Scoring
5. Zero Fake Data Guarantee (No synthetic candles when live feed is empty)
"""
import pytest
from python.trading.execution_engine import ExecutionEngine
from python.brokers.broker_failover import BrokerFailoverManager
from python.intelligence.news_collector import NewsCollectorEngine
from python.data.market_feed import MarketFeed

def test_idempotency_key_generation():
    engine = ExecutionEngine()
    key1 = engine.generate_idempotency_key("NSE:NIFTY50-INDEX", "BUY", "ORB_BREAKOUT")
    key2 = engine.generate_idempotency_key("NSE:NIFTY50-INDEX", "BUY", "ORB_BREAKOUT")
    key3 = engine.generate_idempotency_key("NSE:BANKNIFTY-INDEX", "BUY", "ORB_BREAKOUT")

    assert len(key1) == 32
    assert key1 == key2, "Idempotency key must be identical within the same 5-minute bucket"
    assert key1 != key3, "Idempotency key must differ for different instruments"

def test_risk_gates_kill_switch_active():
    engine = ExecutionEngine()
    candidate = {
        "symbol": "NSE:NIFTY50-INDEX",
        "direction": "BUY",
        "entry_price": 24500.0,
        "quantity": 25
    }
    risk_cfg = {
        "kill_switch_active": 1,
        "live_execution_enabled": 0,
        "max_open_positions": 3,
        "max_daily_loss": 15000.0
    }
    passed, reason = engine.validate_risk_gates(candidate, risk_cfg)
    assert not passed
    assert "EMERGENCY_KILL_SWITCH_ACTIVE" in reason

def test_broker_failover_single_execution_guarantee():
    creds = {
        "FYERS": {"client_id": "TEST_APP", "secret_key": "SECRET"},
        "ANGEL_ONE": {"client_id": "CLIENT123", "api_key": "APIKEY"}
    }
    mgr = BrokerFailoverManager(creds)
    assert mgr.execution_broker_code == "FYERS"

    # Set Angel One as execution broker
    mgr.set_execution_broker("ANGEL_ONE")
    assert mgr.execution_broker_code == "ANGEL_ONE"

    # Attempt to set invalid broker
    mgr.set_execution_broker("NON_EXISTENT")
    assert mgr.execution_broker_code == "ANGEL_ONE", "Invalid broker must not change execution routing"

def test_news_entity_and_sentiment_mapping():
    engine = NewsCollectorEngine()
    
    # Test Bullish News on Reliance
    analysis = engine.analyze_article(
        title="Reliance Industries surges 4% following massive quarterly profit expansion",
        summary="Jio telecom and energy segments register record operational cash flow."
    )
    assert "NSE:RELIANCE-EQ" in analysis["tickers"]
    assert "ENERGY" in analysis["sectors"]
    assert analysis["sentiment_label"] == "BULLISH"
    assert analysis["sentiment_score"] > 0

    # Test Bearish Regulatory Action
    analysis2 = engine.analyze_article(
        title="SEBI initiates probe into market manipulation; penalty expected",
        summary="Regulatory enforcement tightens on derivatives segment."
    )
    assert "MACRO:SEBI" in analysis2["tickers"]
    assert analysis2["sentiment_label"] == "BEARISH"
    assert analysis2["market_impact"] == "HIGH"

def test_zero_fake_data_policy():
    # Attempting to fetch quote for a non-existent fake instrument must return freshness NO_DATA, not fabricated prices
    quote = MarketFeed.get_real_quote("NSE:NONEXISTENTXYZ-EQ")
    assert quote["freshness"] == "NO_DATA"
    assert quote["ltp"] == 0.0

def test_candles_worker_structure():
    from python.workers.candles_worker import get_chart_data
    res = get_chart_data("NSE:NIFTY50-INDEX", timeframe="5m", count=30)
    assert res["status"] == "success"
    assert "candles" in res
    assert "volume" in res
    assert "overlays" in res
    assert "vwap" in res["overlays"]
    assert "ema9" in res["overlays"]
    assert len(res["candles"]) > 0

    first_candle = res["candles"][0]
    assert "time" in first_candle
    assert "open" in first_candle
    assert "high" in first_candle
    assert "low" in first_candle
    assert "close" in first_candle
    assert first_candle["high"] >= first_candle["low"]

def test_ai_copilot_verdict_and_evidence():
    from python.intelligence.chat_assistant import generate_assistant_response
    res = generate_assistant_response("Why NO TRADE on NIFTY right now?", symbol="NSE:NIFTY50-INDEX", mode="general")
    assert res["status"] == "success"
    assert "response" in res
    assert "evidence" in res
    assert "ltp" in res["evidence"]
    assert "vwap" in res["evidence"]
    assert res["evidence"]["ltp"] > 0
    assert "Verdict & Summary" in res["response"]
    assert "Risk & Invalidation Safeguard" in res["response"]

def test_continuous_trading_worker_market_hours_logic():
    from python.workers.continuous_trading_worker import ContinuousTradingWorker
    from datetime import datetime, timezone
    from zoneinfo import ZoneInfo
    IST = ZoneInfo("Asia/Kolkata")

    worker = ContinuousTradingWorker(mode="paper")
    # Tuesday 10:30 IST -> Market Open
    t_open = datetime(2026, 11, 3, 10, 30, tzinfo=IST)
    assert worker.is_market_hours(t_open) is True

    # Tuesday 08:30 IST -> Pre-market
    t_pre = datetime(2026, 11, 3, 8, 30, tzinfo=IST)
    assert worker.is_market_hours(t_pre) is False

    # Tuesday 16:00 IST -> Post-market
    t_post = datetime(2026, 11, 3, 16, 0, tzinfo=IST)
    assert worker.is_market_hours(t_post) is False

    # Sunday 12:00 IST -> Weekend
    t_weekend = datetime(2026, 11, 1, 12, 0, tzinfo=IST)
    assert worker.is_market_hours(t_weekend) is False

