"""
GraphQL server implementation for MarkiTect.

Provides a standalone GraphQL server and integration components
for serving the MarkiTect GraphQL API.
"""

import json
from typing import Optional, Dict, Any
from pathlib import Path

try:
    from flask import Flask, request, jsonify
    from flask_cors import CORS
    FLASK_AVAILABLE = True
except ImportError:
    FLASK_AVAILABLE = False

from .schema import schema
from .resolvers import Query


class GraphQLServer:
    """GraphQL server for MarkiTect API."""

    def __init__(self, db_path: Optional[str] = None, enable_cors: bool = True):
        """
        Initialize GraphQL server.

        Args:
            db_path: Path to MarkiTect database
            enable_cors: Enable CORS for web browser access
        """
        self.db_path = db_path or self._get_default_db_path()
        self.enable_cors = enable_cors
        self.app = None

        if not FLASK_AVAILABLE:
            raise ImportError(
                "Flask is required for GraphQL server. Install with: pip install flask flask-cors"
            )

    def _get_default_db_path(self) -> str:
        """Get default database path."""
        from .resolvers import get_default_database_path
        return get_default_database_path()

    def create_app(self) -> Flask:
        """Create Flask application with GraphQL endpoint."""
        app = Flask(__name__)

        if self.enable_cors:
            CORS(app)

        @app.route('/graphql', methods=['POST'])
        def graphql_endpoint():
            """Handle GraphQL requests."""
            try:
                # Parse request data
                data = request.get_json()
                if not data:
                    return jsonify({'error': 'No JSON data provided'}), 400

                query = data.get('query')
                variables = data.get('variables', {})
                operation_name = data.get('operationName')

                if not query:
                    return jsonify({'error': 'No query provided'}), 400

                # Execute GraphQL query
                result = schema.execute(
                    query,
                    variables=variables,
                    operation_name=operation_name,
                    context={'db_path': self.db_path}
                )

                # Format response
                response_data = {'data': result.data}
                if result.errors:
                    response_data['errors'] = [
                        {'message': str(error)} for error in result.errors
                    ]

                return jsonify(response_data)

            except Exception as e:
                return jsonify({
                    'errors': [{'message': f'Server error: {str(e)}'}]
                }), 500

        @app.route('/graphql', methods=['GET'])
        def graphql_playground():
            """Serve GraphQL playground for development."""
            return '''
            <!DOCTYPE html>
            <html>
            <head>
                <title>MarkiTect GraphQL Playground</title>
                <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css" />
            </head>
            <body>
                <div id="root">
                    <style>
                        body { margin: 0; font-family: Open Sans, sans-serif; overflow: hidden; }
                        #root { height: 100vh; }
                    </style>
                </div>
                <script src="https://cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js"></script>
                <script>
                window.addEventListener('load', function (event) {
                    GraphQLPlayground.init(document.getElementById('root'), {
                        endpoint: '/graphql',
                        settings: {
                            'general.betaUpdates': false,
                            'editor.theme': 'dark',
                            'editor.reuseHeaders': true,
                            'tracing.hideTracingResponse': true,
                        }
                    })
                })
                </script>
            </body>
            </html>
            '''

        @app.route('/schema', methods=['GET'])
        def get_schema():
            """Get GraphQL schema definition."""
            try:
                from graphql.utilities import print_schema
                schema_sdl = print_schema(schema.graphql_schema)
            except (AttributeError, ImportError):
                # Fallback to simple introspection
                schema_sdl = str(schema)

            return jsonify({
                'schema': schema_sdl
            })

        @app.route('/health', methods=['GET'])
        def health_check():
            """Health check endpoint."""
            try:
                # Test database connection
                import sqlite3
                conn = sqlite3.connect(self.db_path)
                cursor = conn.cursor()
                cursor.execute("SELECT 1")
                conn.close()

                return jsonify({
                    'status': 'healthy',
                    'database': 'connected',
                    'database_path': self.db_path
                })
            except Exception as e:
                return jsonify({
                    'status': 'unhealthy',
                    'database': 'error',
                    'error': str(e)
                }), 500

        self.app = app
        return app

    def run(self, host: str = '127.0.0.1', port: int = 5000, debug: bool = False):
        """
        Run the GraphQL server.

        Args:
            host: Host to bind to
            port: Port to bind to
            debug: Enable debug mode
        """
        if not self.app:
            self.create_app()

        print(f"🚀 MarkiTect GraphQL Server starting...")
        print(f"🔗 GraphQL endpoint: http://{host}:{port}/graphql")
        print(f"🎮 GraphQL playground: http://{host}:{port}/graphql")
        print(f"📊 Schema introspection: http://{host}:{port}/schema")
        print(f"❤️  Health check: http://{host}:{port}/health")

        self.app.run(host=host, port=port, debug=debug)


class GraphQLClient:
    """Simple GraphQL client for testing and CLI integration."""

    def __init__(self, endpoint: str = "http://localhost:5000/graphql"):
        """
        Initialize GraphQL client.

        Args:
            endpoint: GraphQL endpoint URL
        """
        self.endpoint = endpoint

    def execute(self, query: str, variables: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        Execute GraphQL query.

        Args:
            query: GraphQL query string
            variables: Query variables

        Returns:
            Query result dictionary
        """
        try:
            import requests

            payload = {
                'query': query,
                'variables': variables or {}
            }

            response = requests.post(
                self.endpoint,
                json=payload,
                headers={'Content-Type': 'application/json'}
            )

            return response.json()

        except ImportError:
            raise ImportError("requests is required for GraphQL client. Install with: pip install requests")

    def execute_local(self, query: str, variables: Optional[Dict[str, Any]] = None, context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        Execute GraphQL query directly (without HTTP).

        Args:
            query: GraphQL query string
            variables: Query variables
            context: GraphQL context

        Returns:
            Query result dictionary
        """
        result = schema.execute(
            query,
            variables=variables or {},
            context=context or {}
        )

        response_data = {'data': result.data}
        if result.errors:
            response_data['errors'] = [
                {'message': str(error)} for error in result.errors
            ]

        return response_data