"""
OpenSoul MCP - Open Source Personality Profiling System

A structured self-logging system based on MCP Protocol.
Records the divergence between AI suggestions and human decisions.

License: MIT
Author: OpenSoul Contributors
"""

import asyncio
import json
import sys
import os
from pathlib import Path
from typing import Callable, Optional

# Add src to path
sys.path.insert(0, str(Path(__file__).parent))

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types

# Import local modules
from storage import db as soul_db
from storage import chain as soul_chain

# Initialize database
soul_db.init_db()
server = Server("opensoul")


# ── Tool Registration ───────────────────────────────────────────────────

@server.list_tools()
async def list_tools():
    """List all available MCP tools."""
    S = {"type": "object", "properties": {}}

    def prop(**kw): 
        return {"type": "object", "properties": kw}
    
    def str_prop(desc): 
        return {"type": "string", "description": desc}
    
    def arr_prop(desc): 
        return {"type": "array", "items": {"type": "string"}, "description": desc}
    
    def num_prop(desc): 
        return {"type": "number", "description": desc}
    
    # Common emotion properties
    _EMO = {
        "emotion_valence": num_prop("Emotion valence -1.0 (negative) ~ 1.0 (positive)"),
        "emotion_intensity": num_prop("Emotion intensity 0.0 ~ 1.0"),
        "emotion_duration": str_prop("Duration: minutes/hours/days/weeks"),
        "emotion_trigger_type": str_prop("Trigger type: person/event/thought/environment"),
        "emotion_trigger_ref": str_prop("Trigger reference (person name/event/relation_id)"),
        "emotion_label": str_prop("Standardized emotion label"),
        "emotion_secondary": str_prop("Secondary emotion"),
    }
    
    # Common timeline properties
    _TL = {
        "memory_time": str_prop("Memory time description (e.g., 'childhood', 'last summer')"),
        "memory_time_start": str_prop("Memory time start ISO (e.g., '1995-06-01')"),
        "memory_time_end": str_prop("Memory time end ISO"),
        "memory_time_precision": str_prop("Precision: exact/year/decade/period/vague"),
        "time_direction": str_prop("Time direction: past/present/future/timeless"),
    }
    
    def T(name, description, schema):
        return types.Tool(name=name, description=description, inputSchema=schema)

    return [
        # Recording Tools
        T("record_soul",
          "Record a soul event - the divergence between AI suggestion and human decision.",
          prop(
              context=str_prop("What was happening"),
              ai_suggestion=str_prop("What AI suggested (can be empty)"),
              human_decision=str_prop("What you actually decided"),
              divergence_reason=str_prop("Why you made this choice"),
              tags=arr_prop("Tags: intuition/risk/aesthetic/ethics/trust/identity/meaning-first"),
              notes=str_prop("Additional notes"),
              emotional_state=str_prop("Emotional state: calm/anxious/excited/tired/determined..."),
              energy=str_prop("Energy level: high/medium/low"),
              body_state=str_prop("Body state: tired/alert/sick..."),
              decision_layer=str_prop("Decision layer: body/habit/identity/values/survival"),
              time_horizon=str_prop("Time horizon: immediate/days/months/years/lifetime"),
              social_context=str_prop("Social context: alone/with_family/with_colleagues..."),
              **_TL, **_EMO,
          )),

        T("record_state",
          "Record a state snapshot - independent of specific decisions.",
          prop(
              emotional_state=str_prop("Emotional state"),
              energy=str_prop("Energy level: high/medium/low"),
              body_state=str_prop("Body state"),
              social_context=str_prop("Social context"),
              environment=str_prop("Physical environment"),
              notes=str_prop("Other observations"),
              tags=arr_prop("Tags"),
              **_TL, **_EMO,
          )),

        T("record_contradiction",
          "Explicitly record a contradiction between two decisions.",
          prop(
              description=str_prop("What is the contradiction"),
              soul_id_a={"type": "integer", "description": "First soul event id"},
              soul_id_b={"type": "integer", "description": "Second soul event id"},
              analysis=str_prop("Analysis of the contradiction"),
              resolution=str_prop("Resolution: open/resolved/paradox"),
              tags=arr_prop("Tags"),
              **_TL,
          )),

        T("record_silence",
          "Record a silence, avoidance, or incomplete expression.",
          prop(
              topic=str_prop("What topic was being discussed"),
              silence_form=str_prop("Form: no_response/deflection/half_said/explicit_refusal/pause"),
              observation=str_prop("Observer's perspective"),
              tags=arr_prop("Tags"),
              **_TL,
          )),

        T("record_artifact",
          "Record a multimodal artifact reference - image, audio, document, etc.",
          prop(
              artifact_type=str_prop("Type: image/audio/document/url/screenshot/other"),
              description=str_prop("What this artifact records"),
              path=str_prop("File path or URL"),
              linked_soul_id={"type": "integer", "description": "Associated soul event id"},
              tags=arr_prop("Tags"),
              **_TL,
          )),

        T("ingest_media",
          "Ingest media file (image/audio/video) into soul archive.",
          prop(
              file_path=str_prop("Absolute file path"),
              artifact_type=str_prop("Type: image/audio/video"),
              extra_context=str_prop("Additional context for AI analysis"),
              is_soul_photo={"type": "boolean", "description": "Is this a soul photo (store binary)"},
              linked_soul_id={"type": "integer", "description": "Associated soul event id"},
              tags=arr_prop("Tags"),
          )),

        # Query Tools
        T("list_souls", "List recent soul events",
          prop(limit={"type": "integer"}, tag=str_prop("Filter by tag"))),

        T("search_souls", "Search soul events by keyword",
          prop(keyword=str_prop("Search term"))),

        T("query_souls", "Semantic search soul events",
          prop(query=str_prop("Natural language query"), limit={"type": "integer"})),

        T("get_soul_by_id", "Get a specific soul event by ID",
          prop(soul_id={"type": "integer", "description": "Soul event ID"})),

        # Profile Tools
        T("set_profile", "Set or update a dimension in personality profile",
          prop(
              key=str_prop("Attribute name: name/personality/preference/belief..."),
              value=str_prop("Attribute value"),
              category=str_prop("Category: identity/personality/preference/history/belief"),
              **_TL,
          )),

        T("get_profile", "Read personality profile",
          prop(category=str_prop("Category filter (empty for all)"))),

        T("get_portrait", "Get full personality portrait", S),

        # Philosophy Tools
        T("add_philosophy", "Record a decision philosophy or principle",
          prop(
              principle=str_prop("One-sentence statement of principle"),
              source=str_prop("Source"),
              examples=arr_prop("Specific examples"),
              **_TL,
          )),

        T("list_philosophy", "List all recorded philosophies", S),

        # Analysis Tools
        T("analyze_tags", "Analyze tag distribution", S),
        T("analyze_coverage", "Analyze 7-dimension coverage matrix", S),
        T("summarize_souls", "Summarize all soul events and extract patterns", S),

        # System Tools
        T("verify_chain", "Verify hash chain integrity", S),
        T("health_check", "System health check", S),
        T("get_stats", "Get database statistics", S),
    ]


# ── Tool Handlers ────────────────────────────────────────────────────────

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list:
    """Handle tool calls."""
    try:
        if name == "record_soul":
            result = soul_db.record_soul(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "record_state":
            result = soul_db.record_state(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "record_contradiction":
            result = soul_db.record_contradiction(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "record_silence":
            result = soul_db.record_silence(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "record_artifact":
            result = soul_db.record_artifact(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "ingest_media":
            result = soul_db.ingest_media(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "list_souls":
            result = soul_db.list_souls(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "search_souls":
            result = soul_db.search_souls(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "query_souls":
            result = soul_db.query_souls(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "get_soul_by_id":
            result = soul_db.get_soul_by_id(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "set_profile":
            result = soul_db.set_profile(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "get_profile":
            result = soul_db.get_profile(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "get_portrait":
            result = soul_db.get_portrait()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "add_philosophy":
            result = soul_db.add_philosophy(**arguments)
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "list_philosophy":
            result = soul_db.list_philosophy()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "analyze_tags":
            result = soul_db.analyze_tags()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "analyze_coverage":
            result = soul_db.analyze_coverage()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "summarize_souls":
            result = soul_db.summarize_souls()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "verify_chain":
            result = soul_chain.verify_chain()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "health_check":
            result = soul_db.health_check()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        elif name == "get_stats":
            result = soul_db.get_stats()
            return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
        
        else:
            return [types.TextContent(type="text", text=f"Unknown tool: {name}")]
    
    except Exception as e:
        return [types.TextContent(type="text", text=f"Error: {str(e)}")]


# ── Main Entry ───────────────────────────────────────────────────────────

async def main():
    """Main entry point."""
    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            server.create_initialization_options()
        )


if __name__ == "__main__":
    asyncio.run(main())
