import argparse
from quart import Quart, jsonify, request

import asyncio
from hypercorn.config import Config
from hypercorn.asyncio import serve

from .processors import ProcessorRegistry
from .pipeline import SearchPipeline
from .utils import logger

from .config.load import load_config

app = Quart(__name__)
config = None

@app.before_serving
async def startup():
    """Initialize resources before the server starts."""
    global config
    await load_config(config)


@app.route('/search', methods=['POST'])
@app.route('/query', methods=['POST']) # deprecated
async def process_query():
    """API endpoint for processing requests."""

    try:
        data = await request.get_json()
        if not data:
            return jsonify({"error": "No data provided"}), 400
        
        service = data.pop('service')
        if not ProcessorRegistry.has_service(service, 'search'):
            return jsonify({"error": "Unsupported service"}), 400

        result = await ProcessorRegistry.get(service, 'search').submit(data)
        return jsonify(result)

    except Exception as e:
        logger.error(f"Error processing request: {e}")
        return jsonify({"error": str(e)}), 500


@app.route('/score', methods=['POST'])
async def process_scoring():
    """API endpoint for processing requests."""

    try:
        data = await request.get_json()
        if not data:
            return jsonify({"error": "No data provided"}), 400

        service = data.pop('service')
        if not ProcessorRegistry.has_service(service, 'score'):
            return jsonify({"error": "Unsupported service"}), 400

        result = await ProcessorRegistry.get(service, 'score').submit(data)
        return jsonify(result)

    except Exception as e:
        logger.error(f"Error processing request: {e}")
        return jsonify({"error": str(e)}), 500


@app.route('/content', methods=['POST'])
async def process_get_content():
    try:
        data = await request.get_json()
        if not data or 'id' not in data:
            return jsonify({"error": "No id provided"}), 400

        if not ProcessorRegistry.has_service(data['collection'], 'content'):
            return jsonify({"error": "Unsupported collection"}), 400

        result = await ProcessorRegistry.get(data['collection'], 'content').submit(data)
        return jsonify({**data, **result}), 400 if 'error' in result else 200

    except Exception as e:
        logger.error(f"Error processing request: {e}")
        return jsonify({"error": str(e)}), 500


@app.route('/pipeline', methods=['POST'])
async def process_pipeline():
    try:
        data = await request.get_json()
        if not data:
            return jsonify({"error": "No data provided"}), 400
        # required fields
        for field in ['pipeline', 'collection', 'query']:
            if field not in data:
                return jsonify({"error": f"No {field} provided"}), 400

        pipeline = SearchPipeline.from_string(
            data['pipeline'], data['collection'], runtime_kwargs=data.get('runtime_kwargs', {})
        )
        result = await pipeline.run(data['query'])
        return jsonify({**data, **result}), 200 
    
    except Exception as e:
        logger.error(f"Error processing request: {e}")
        return jsonify({"error": str(e)}), 500

@app.route('/ping', methods=['GET'])
async def health_check():
    """Simple health check endpoint."""
    return jsonify({"status": "pong"})


@app.route('/avail', methods=['GET'])
async def get_avail_service():
    return jsonify(ProcessorRegistry.get_all_services())


if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('config', type=str)
    parser.add_argument('--port', type=int, default=5000)
    parser.add_argument('--host', type=str, default='0.0.0.0')
    parser.add_argument('--cache_dir', type=str, default='./.cache')

    args = parser.parse_args()

    config = args.config

    # app.run(host=args.host, port=args.port, use_reloader=False)
    hypercorn_config = Config()
    hypercorn_config.bind = [f"{args.host}:{args.port}"]
    asyncio.run(serve(app, hypercorn_config))
