from flask import Flask, request, jsonify, send_from_directory
import os
import logging
from agent_src.agent import Agent
from agent_src.interfaces import WebAdapter
import uuid
import json

# Path to store skeleton prompts
SKELETON_STORE = os.path.join(os.path.dirname(__file__), "web_skeletons.json")

# Setup logging
LOG_PATH = os.path.join(os.path.dirname(__file__), 'web.log')
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(name)s %(message)s', handlers=[logging.FileHandler(LOG_PATH), logging.StreamHandler()])
logger = logging.getLogger(__name__)

# Optional server-side API key. If set, clients must send it as X-API-KEY header.
SERVER_API_KEY = os.getenv("WEB_API_KEY")


def _require_api_key():
    """Return True if request is authorized or if no server key is configured."""
    if not SERVER_API_KEY:
        return True
    key = request.headers.get("X-API-KEY") or request.args.get("api_key")
    return key == SERVER_API_KEY


def require_auth_or_403():
    if not _require_api_key():
        return jsonify({"error": "unauthorized"}), 401
    return None


def _load_skeletons():
    if not os.path.isfile(SKELETON_STORE):
        return []
    try:
        with open(SKELETON_STORE, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return []


def _save_skeletons(data):
    with open(SKELETON_STORE, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2)

app = Flask(__name__, static_folder='web_static', static_url_path='')


@app.route('/')
def index():
    return send_from_directory(app.static_folder, 'index.html')


@app.route('/api/chat', methods=['POST'])
def chat():
    data = request.get_json() or {}
    instruction = data.get('instruction')
    if not instruction:
        return jsonify({'error': 'missing instruction'}), 400
    logger.info("/api/chat received instruction: %s", instruction)

    # auth
    auth_err = require_auth_or_403()
    if auth_err:
        return auth_err

    agent = Agent(ui_adapter=WebAdapter())
    try:
        result = agent.run(instruction)
        logger.info("/api/chat result: %s", result)
        # If agent returned an awaiting token dict, return it directly so clients can handle it
        if isinstance(result, dict) and result.get('awaiting'):
            return jsonify(result)
        return jsonify({'answer': result})
    except Exception as e:
        logger.exception("/api/chat failed: %s", e)
        return jsonify({'error': str(e)}), 500


@app.route('/api/skeletons', methods=['GET'])
def list_skeletons():
    auth_err = require_auth_or_403()
    if auth_err:
        return auth_err
    logger.info("/api/skeletons list")
    return jsonify(_load_skeletons())


@app.route('/api/skeletons', methods=['POST'])
def create_skeleton():
    data = request.get_json() or {}
    name = data.get('name')
    template = data.get('template')
    if not name or not template:
        return jsonify({'error': 'missing name or template'}), 400
    auth_err = require_auth_or_403()
    if auth_err:
        return auth_err

    sk = {'id': str(uuid.uuid4()), 'name': name, 'template': template}
    items = _load_skeletons()
    items.append(sk)
    _save_skeletons(items)
    logger.info("Created skeleton %s", sk['id'])
    return jsonify(sk)


@app.route('/api/skeletons/<skid>', methods=['PUT'])
def update_skeleton(skid):
    auth_err = require_auth_or_403()
    if auth_err:
        return auth_err
    data = request.get_json() or {}
    items = _load_skeletons()
    for it in items:
        if it.get('id') == skid:
            it['name'] = data.get('name', it.get('name'))
            it['template'] = data.get('template', it.get('template'))
            _save_skeletons(items)
            logger.info("Updated skeleton %s", skid)
            return jsonify(it)
    return jsonify({'error': 'not found'}), 404


@app.route('/api/skeletons/<skid>', methods=['DELETE'])
def delete_skeleton(skid):
    auth_err = require_auth_or_403()
    if auth_err:
        return auth_err
    items = _load_skeletons()
    new = [it for it in items if it.get('id') != skid]
    if len(new) == len(items):
        return jsonify({'error': 'not found'}), 404
    _save_skeletons(new)
    logger.info("Deleted skeleton %s", skid)
    return jsonify({'ok': True})


@app.route('/api/respond/<token>', methods=['POST'])
def respond(token):
    data = request.get_json() or {}
    answer = data.get('answer')
    if answer is None:
        return jsonify({'error': 'missing answer'}), 400
    logger.info("/api/respond token=%s answer=%s", token, str(answer)[:200])
    # resume agent
    from agent_src.agent import Agent
    from agent_src import ui_state

    pending = ui_state.PENDING.get(token)
    if not pending:
        logger.warning("unknown respond token: %s", token)
        return jsonify({'error': 'unknown token'}), 404

    # create an agent with same model and adapter (web adapter not needed here)
    agent = Agent(model=pending.get('model'), ui_adapter=WebAdapter())
    result = agent.resume(token, answer)
    logger.info("/api/respond resume result for %s: %s", token, str(result)[:200])
    return jsonify({'result': result})


if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)
