"""세종 상권 살펴보기 API. 운영 환경에서는 waitress와 HTTPS 프록시 사용."""
import logging
import math
import os
from pathlib import Path
from functools import lru_cache
for key in ("OMP_NUM_THREADS", "OPENBLAS_NUM_THREADS", "MKL_NUM_THREADS"):
    os.environ.setdefault(key, "1")
import numpy as np
from flask import Flask, jsonify, render_template, request
from werkzeug.exceptions import HTTPException
try:
    from .engine import 엔진
except ImportError:
    from engine import 엔진


def 숫자정리(value):
    if isinstance(value, dict):
        return {key: 숫자정리(item) for key, item in value.items()}
    if isinstance(value, (list, tuple)):
        return [숫자정리(item) for item in value]
    if isinstance(value, np.generic):
        value = value.item()
    return None if isinstance(value, float) and not math.isfinite(value) else value


@lru_cache(maxsize=1)
def default_engine():
    return 엔진()


def create_app(engine=None):
    app = Flask(__name__)
    from .materials import bp
    app.config['MATERIALS_DIR'] = Path(__file__).resolve().parents[1] / 'public_materials'
    app.register_blueprint(bp)
    app.json.ensure_ascii = False
    app.config["MAX_CONTENT_LENGTH"] = 16 * 1024
    if engine is not None:
        app.extensions["sejong_engine"] = engine
    def model():
        return app.extensions.get("sejong_engine") or default_engine()
    def parameters(category_required=False):
        data = request.get_json(silent=True)
        if not isinstance(data, dict) or isinstance(data.get("lat"), bool) or isinstance(data.get("lon"), bool):
            return None
        try:
            lat, lon = float(data["lat"]), float(data["lon"])
        except (KeyError, ValueError, TypeError, OverflowError):
            return None
        if not model().위치확인(lat, lon):
            return None
        category = data.get("mid")
        if category_required and (not isinstance(category, str) or category not in model().mid_to_cat):
            return None
        return round(lat, 6), round(lon, 6), category
    @app.get("/")
    def index():
        return render_template("index.html")
    @app.get("/healthz")
    def health():
        current = model()
        return jsonify({"status": "ok", "rows": len(current.now), "model_count": len(current.모델), "version": "2"})
    @app.get("/api/meta")
    def metadata():
        response = jsonify(숫자정리(model().메타()))
        response.headers["Cache-Control"] = "public, max-age=300"
        return response
    @app.get("/api/boundary")
    def boundary():
        return jsonify(model().boundary or {"type": "FeatureCollection", "features": []})
    @app.post("/api/analyze")
    def analyze():
        values = parameters(True)
        if values is None:
            return jsonify({"오류": "세종시 경계 안의 위치와 목록에 있는 업종을 골라 주세요."}), 400
        return jsonify(숫자정리(model().분석(*values)))
    @app.post("/api/recommend")
    def compare_categories():
        values = parameters()
        if values is None:
            return jsonify({"오류": "세종시 경계 안의 위치를 골라 주세요."}), 400
        return jsonify(숫자정리(model().업종추천(values[0], values[1])))
    @app.after_request
    def headers(response):
        response.headers.update({"X-Content-Type-Options": "nosniff", "Referrer-Policy": "strict-origin-when-cross-origin", "X-Frame-Options": "SAMEORIGIN"})
        response.headers.setdefault("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://*.tile.openstreetmap.org https://*.tile.openstreetmap.fr; connect-src 'self'; frame-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'")
        if request.path.startswith("/api/") and request.method == "POST":
            response.headers["Cache-Control"] = "no-store"
        return response
    @app.errorhandler(HTTPException)
    def http_error(error):
        messages = {404: "요청한 주소가 없습니다.", 405: "지원하지 않는 요청 방식입니다.", 413: "요청 내용이 너무 큽니다."}
        return jsonify({"오류": messages.get(error.code, "요청을 처리하지 못했습니다.")}), error.code
    @app.errorhandler(Exception)
    def unexpected(error):
        logging.getLogger(__name__).exception("요청 처리 실패")
        return jsonify({"오류": "일시적으로 분석하지 못했습니다. 잠시 후 다시 시도해 주세요."}), 500
    return app


app = create_app()
if __name__ == "__main__":
    from waitress import serve
    logging.basicConfig(level=logging.INFO)
    default_engine()
    serve(app, host=os.environ.get("HOST", "127.0.0.1"), port=int(os.environ.get("PORT", "5000")), threads=4)
