import datetime as dt
import os
from decimal import Decimal

from flask import Flask, g, jsonify, redirect, request, url_for
from flask.json.provider import DefaultJSONProvider
from werkzeug.exceptions import HTTPException

from auth import ApiError
from db import close_db


def _json_default(o):
    if isinstance(o, (dt.datetime, dt.date)):
        return o.isoformat()
    if isinstance(o, Decimal):
        return float(o)
    raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")


class AppJSONProvider(DefaultJSONProvider):
    ensure_ascii = False          # عربي مقروء في الـ JSON
    default = staticmethod(_json_default)


def create_app():
    app = Flask(__name__)
    app.config.from_object("config.Config")
    app.config.from_pyfile(os.path.join(app.root_path, "config_local.py"), silent=True)
    app.json = AppJSONProvider(app)

    if not app.debug and "CHANGE-ME" in (app.config["SECRET_KEY"], app.config["JWT_SECRET"]):
        raise RuntimeError("غيّر SECRET_KEY و JWT_SECRET في config_local.py قبل التشغيل")

    from api import bp as api_bp
    from admin_panel import bp as admin_bp
    app.register_blueprint(api_bp, url_prefix="/api")
    app.register_blueprint(admin_bp, url_prefix="/admin")
    app.teardown_appcontext(close_db)

    @app.get("/")
    def index():
        return redirect(url_for("admin.captains"))

    @app.after_request
    def finish_transaction(resp):
        db = g.get("db")
        if db is not None:
            if resp.status_code < 400:
                db.commit()
            else:
                db.rollback()
        return resp

    @app.errorhandler(ApiError)
    def handle_api_error(e):
        return jsonify(error=e.code, message=e.message, **e.extra), e.status

    @app.errorhandler(HTTPException)
    def handle_http(e):
        if request.path.startswith("/api"):
            return jsonify(error=e.name.lower().replace(" ", "_"), message=e.description), e.code
        return e

    @app.errorhandler(Exception)
    def handle_unexpected(e):
        app.logger.exception(e)
        if request.path.startswith("/api"):
            return jsonify(error="server_error", message="حدث خطأ في الخادم"), 500
        return "Server error", 500

    return app
