import sys
import os
import time
import logging
import platform

# Mock platform BEFORE anything else is loaded
original_system = platform.system
platform.system = lambda: "Windows"

# Add paths to use mesh-sdk
_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(_root)

from mesh_core.engines.node import MeshNodeCore
from mesh_core.transport.grpc import GrpcMeshTransport
from mesh_core import agent_pb2, agent_pb2_grpc
import grpc

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("FakedWindowsNode")

def get_stub():
    target = os.getenv("GRPC_ENDPOINT", "192.168.68.113:50051")
    logger.info(f"Connecting to {target}...")
    channel = grpc.insecure_channel(target)
    stub = agent_pb2_grpc.AgentOrchestratorStub(channel)
    return stub, channel

class FakedWindowsNode(MeshNodeCore):
    def __init__(self, node_id: str, auth_token: str):
        self.transport = GrpcMeshTransport(node_id, get_stub, auth_token=auth_token)
        super().__init__(node_id, self.transport)
        
        self.on_task = self.handle_task
        self.on_sync = self.handle_sync
        self.on_ready = lambda _: logger.info(f"[*] FakedWindowsNode '{node_id}' is AUTHORIZED and ONLINE.")
        self.on_disconnect = lambda: logger.warning("[!] Lost connection to Hub.")

    def handle_task(self, task):
        logger.info(f"[Task] Executing: {task.task_id} (Type: {task.task_type})")
        payload = task.payload_json
        logger.info(f"[Task] Payload: {payload}")
        
        # Simulate Terminal output stream if it's an interactive task
        if "tty" in payload or task.task_type == "interactive_shell":
            import json
            try:
                cmd_data = json.loads(payload) if isinstance(payload, str) else payload
                tty_input = cmd_data.get("tty", "")
                if tty_input:
                    # Echo back the input and a prompt
                    logger.info(f"[PTY] Echoing input: {repr(tty_input)}")
                    resp = agent_pb2.TaskResponse(
                        task_id=task.task_id,
                        stdout=tty_input + "\r\nC:\\FakeWindows> ",
                        status=0
                    )
                    self.send_message(agent_pb2.ClientTaskMessage(task_response=resp))
            except Exception as e:
                pass
        else:
            response = agent_pb2.TaskResponse(
                task_id=task.task_id, 
                stdout=f"C:\\> Faked Windows Execution Success!\nReceived command: {payload}", 
                status=0
            )
            self.send_message(agent_pb2.ClientTaskMessage(task_response=response))

    def handle_sync(self, sync_msg):
        logger.info(f"[Sync] Received Sync Message: {sync_msg.WhichOneof('payload')}")
        if sync_msg.HasField('control'):
            ctrl = sync_msg.control
            if ctrl.action == agent_pb2.SyncControl.LIST:
                logger.info(f"[Sync] Answering LIST command for path: {ctrl.path}")
                # Hardcode a fake Windows directory response
                manifest = agent_pb2.DirectoryManifest(
                    root_path=ctrl.path,
                    files=[
                        agent_pb2.FileInfo(path="fake_windows_folder", size=0, is_dir=True),
                        agent_pb2.FileInfo(path="boot.ini", size=1024, is_dir=False),
                        agent_pb2.FileInfo(path="autoexec.bat", size=256, is_dir=False)
                    ],
                    is_final=True
                )
                response = agent_pb2.ClientTaskMessage(
                    file_sync=agent_pb2.FileSyncMessage(
                        session_id=sync_msg.session_id,
                        task_id=sync_msg.task_id,
                        manifest=manifest
                    )
                )
                self.send_message(response)


    def start_health_reporting(self):
        import threading
        def _report():
            while not self._stop_event.is_set():
                if self.transport.is_connected():
                    hb = agent_pb2.Heartbeat(
                        node_id=self.node_id,
                        cpu_usage_percent=12.5,
                        memory_usage_percent=45.0,
                        active_worker_count=0,
                        max_worker_capacity=5,
                        status_message="Windows node running fine",
                        running_task_ids=[],
                        cpu_count=8,
                        memory_used_gb=16.0,
                        memory_total_gb=32.0
                    )
                    self.transport.send_health(hb)
                time.sleep(5)
        threading.Thread(target=_report, daemon=True, name="HealthReporter").start()

if __name__ == "__main__":
    import requests
    
    API_URL = "http://192.168.68.113:8002/api/v1"
    HEADERS = {
        "X-User-ID": "37471c66-9da0-42a5-8b00-8b2f5bb46baa", # Auto-bypass user
        "X-Proxy-Secret": "aYc2j1lYUUZXkBFFUndnleZI"
    }
    NODE_ID = "faked-windows-node"
    
    # 1. Register the node to get an invite token
    logger.info(f"Registering node '{NODE_ID}' via REST API...")
    try:
        # First check if it exists and delete it, or just create it
        requests.delete(f"{API_URL}/nodes/admin/{NODE_ID}", headers=HEADERS)
        
        res = requests.post(f"{API_URL}/nodes/admin", headers=HEADERS, json={
            "node_id": NODE_ID,
            "display_name": "Faked Windows Node",
            "description": "Mocked Windows client for debugging"
        })
        res.raise_for_status()
        auth_token = res.json().get("invite_token")
        logger.info(f"Successfully registered. Invite Token: {auth_token[:8]}...")
    except Exception as e:
        logger.error(f"Failed to register node: {e}")
        if hasattr(e, 'response') and e.response is not None:
            logger.error(f"Response: {e.response.text}")
        sys.exit(1)

    # 2. Start the Mesh Node
    node = FakedWindowsNode(NODE_ID, auth_token)
    
    if node.start():
        node.start_health_reporting()
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            node.stop()
