#!/usr/bin/env python3
"""
Generate jump-in/jump-out signals from order flow graph.

This script:
1. Loads order flow graph
2. Finds anomalies (absorption, squeeze, exhaustion)
3. Generates trading signals with entry/exit/target
4. Outputs signals for manual trading
"""

import json
from pathlib import Path
from typing import Dict, List
from datetime import datetime


class SignalGenerator:
    """Generate trading signals from order flow anomalies."""

    def __init__(self, graph_file: Path):
        self.graph_file = graph_file
        self.graph = self.load_graph()

    def load_graph(self) -> Dict:
        """Load order flow graph from JSON."""
        print(f"Loading graph from {self.graph_file}...")

        with open(self.graph_file, 'r') as f:
            graph = json.load(f)

        print(f"  ✓ Loaded {len(graph['entities'])} entities, {len(graph['relationships'])} relationships")
        return graph

    def get_anomalies(self) -> List[Dict]:
        """Extract all anomalies from graph."""
        anomalies = []

        for entity in self.graph['entities']:
            if entity['type'] == 'Anomaly':
                anomaly = {
                    'id': entity['id'],
                    'name': entity['name'],
                    'type': entity['properties']['type'],
                    'direction': entity['properties']['direction'],
                    'severity': entity['properties']['severity'],
                    'reason': entity['properties'].get('reason', '')
                }

                # Find associated price level
                for rel in self.graph['relationships']:
                    if rel['type'] == 'HAS_ANOMALY' and rel['to'] == entity['id']:
                        price_level_id = rel['from']
                        price_entity = next(e for e in self.graph['entities'] if e['id'] == price_level_id)
                        anomaly['price'] = price_entity['properties']['price']
                        anomaly['metrics'] = price_entity['properties']
                        break

                anomalies.append(anomaly)

        return anomalies

    def generate_absorption_signal(self, anomaly: Dict) -> Dict:
        """Generate signal from absorption anomaly."""
        direction = anomaly['direction']
        entry_price = anomaly['price']
        severity = anomaly['severity']

        # Calculate targets and stops based on severity
        if direction == 'bullish':
            # Absorbing sellers = go long
            target = entry_price + (2.0 * severity)  # 2 points max
            stop = entry_price - (0.5 * severity)     # 0.5 points max
        else:
            # Absorbing buyers = go short
            target = entry_price - (2.0 * severity)
            stop = entry_price + (0.5 * severity)

        return {
            'type': 'ABSORPTION',
            'direction': direction,
            'entry_price': entry_price,
            'target_price': round(target, 2),
            'stop_price': round(stop, 2),
            'confidence': round(min(severity + 0.1, 0.95), 2),
            'risk_reward': round(abs(target - entry_price) / abs(entry_price - stop), 2),
            'reason': f"Absorption detected: {anomaly['reason']}",
            'timestamp': datetime.now().isoformat()
        }

    def generate_squeeze_signal(self, anomaly: Dict) -> Dict:
        """Generate signal from squeeze anomaly."""
        direction = anomaly['direction']
        entry_price = anomaly['price']
        severity = anomaly['severity']

        # Squeeze = wait for breakout, then jump in
        # For now, assume entry at current level with tight stop
        if direction == 'bullish':
            target = entry_price + (3.0 * severity)  # Bigger move expected
            stop = entry_price - (0.3 * severity)     # Tight stop
        else:
            target = entry_price - (3.0 * severity)
            stop = entry_price + (0.3 * severity)

        return {
            'type': 'SQUEEZE',
            'direction': direction,
            'entry_price': entry_price,
            'target_price': round(target, 2),
            'stop_price': round(stop, 2),
            'confidence': round(min(severity + 0.05, 0.90), 2),
            'risk_reward': round(abs(target - entry_price) / abs(entry_price - stop), 2),
            'reason': f"Squeeze detected: {anomaly['reason']}",
            'timestamp': datetime.now().isoformat()
        }

    def generate_exhaustion_signal(self, anomaly: Dict) -> Dict:
        """Generate signal from exhaustion anomaly."""
        direction = anomaly['direction']
        entry_price = anomaly['price']
        severity = anomaly['severity']

        # Exhaustion = reversal play, smaller targets
        if direction == 'bullish':
            # Buyers exhausted = short reversal
            target = entry_price - (1.5 * severity)
            stop = entry_price + (0.5 * severity)
            trade_direction = 'bearish'
        elif direction == 'bearish':
            # Sellers exhausted = long reversal
            target = entry_price + (1.5 * severity)
            stop = entry_price - (0.5 * severity)
            trade_direction = 'bullish'
        else:
            # Neutral exhaustion = skip
            return None

        return {
            'type': 'EXHAUSTION',
            'direction': trade_direction,
            'entry_price': entry_price,
            'target_price': round(target, 2),
            'stop_price': round(stop, 2),
            'confidence': round(min(severity + 0.05, 0.75), 2),  # Lower confidence
            'risk_reward': round(abs(target - entry_price) / abs(entry_price - stop), 2),
            'reason': f"Exhaustion detected: {anomaly['reason']}",
            'timestamp': datetime.now().isoformat()
        }

    def generate_all_signals(self) -> List[Dict]:
        """Generate trading signals from all anomalies."""
        print("\n" + "="*80)
        print("GENERATING TRADING SIGNALS")
        print("="*80)

        anomalies = self.get_anomalies()
        signals = []

        print(f"\nFound {len(anomalies)} anomalies")

        for anomaly in anomalies:
            print(f"\nProcessing: {anomaly['type']} at {anomaly['price']}")

            if anomaly['type'] == 'ABSORPTION':
                signal = self.generate_absorption_signal(anomaly)
                signals.append(signal)
                print(f"  ✓ Signal: {signal['direction']} {signal['type']}")
                print(f"    Entry: {signal['entry_price']}, Target: {signal['target_price']}, Stop: {signal['stop_price']}")
                print(f"    Confidence: {signal['confidence']}, R:R: {signal['risk_reward']}")

            elif anomaly['type'] == 'SQUEEZE':
                signal = self.generate_squeeze_signal(anomaly)
                signals.append(signal)
                print(f"  ✓ Signal: {signal['direction']} {signal['type']}")
                print(f"    Entry: {signal['entry_price']}, Target: {signal['target_price']}, Stop: {signal['stop_price']}")
                print(f"    Confidence: {signal['confidence']}, R:R: {signal['risk_reward']}")

            elif anomaly['type'] == 'EXHAUSTION':
                signal = self.generate_exhaustion_signal(anomaly)
                if signal:
                    signals.append(signal)
                    print(f"  ✓ Signal: {signal['direction']} {signal['type']}")
                    print(f"    Entry: {signal['entry_price']}, Target: {signal['target_price']}, Stop: {signal['stop_price']}")
                    print(f"    Confidence: {signal['confidence']}, R:R: {signal['risk_reward']}")
                else:
                    print(f"  ⊘ Skipped: Neutral exhaustion")

        # Sort by confidence
        signals.sort(key=lambda x: x['confidence'], reverse=True)

        print(f"\n✓ Generated {len(signals)} trading signals")

        return signals

    def save_signals(self, signals: List[Dict], filename: str):
        """Save signals to JSON file."""
        output_file = self.graph_file.parent / filename

        output_data = {
            'metadata': {
                'generated_at': datetime.now().isoformat(),
                'signal_count': len(signals),
                'source_graph': str(self.graph_file)
            },
            'signals': signals
        }

        with open(output_file, 'w') as f:
            json.dump(output_data, f, indent=2)

        print(f"\n✓ Saved signals to {output_file}")


def print_signal_summary(signals: List[Dict]):
    """Print summary of generated signals."""
    print("\n" + "="*80)
    print("SIGNAL SUMMARY")
    print("="*80)

    # Group by type
    by_type = {}
    for signal in signals:
        stype = signal['type']
        if stype not in by_type:
            by_type[stype] = []
        by_type[stype].append(signal)

    for stype, sigs in by_type.items():
        print(f"\n{stype} ({len(sigs)} signals):")

        for i, sig in enumerate(sigs[:5], 1):  # Show top 5
            print(f"  {i}. {sig['direction'].upper()}")
            print(f"     Entry: {sig['entry_price']}, Target: {sig['target_price']}, Stop: {sig['stop_price']}")
            print(f"     Confidence: {sig['confidence']}, R:R: {sig['risk_reward']}")

    # Show best opportunities
    print("\n" + "="*80)
    print("BEST OPPORTUNITIES (Confidence > 0.6, R:R > 1.5)")
    print("="*80)

    best_signals = [s for s in signals if s['confidence'] > 0.6 and s['risk_reward'] > 1.5]
    best_signals.sort(key=lambda x: x['confidence'] * x['risk_reward'], reverse=True)

    for i, sig in enumerate(best_signals[:3], 1):
        print(f"\n{i}. {sig['type']} - {sig['direction'].upper()}")
        print(f"   {sig['reason']}")
        print(f"   Entry: ${sig['entry_price']}, Target: ${sig['target_price']}, Stop: ${sig['stop_price']}")
        print(f"   Confidence: {sig['confidence']}, Risk-Reward: {sig['risk_reward']}")


def main():
    """Main signal generation script."""
    print("="*80)
    print("ORDER FLOW SIGNAL GENERATOR")
    print("="*80)

    # Paths
    graph_file = Path("/home/ubuntu/.hermes/workspace/projects/ORDER_FLOW_GRAPH/data/order_flow_graph_phase1.json")

    # Generate signals
    generator = SignalGenerator(graph_file)
    signals = generator.generate_all_signals()

    # Save signals
    generator.save_signals(signals, "signals_phase1.json")

    # Print summary
    print_signal_summary(signals)

    print("\n" + "="*80)
    print("SIGNAL GENERATION COMPLETE")
    print("="*80)


if __name__ == "__main__":
    main()
