import os
import logging
from flask import Flask, request, session, g, render_template
from app.config import config_by_name
from app.extensions import db, login_manager
from app.i18n import init_translations, get_translator, RTL_LANGS

logger = logging.getLogger(__name__)


def create_app(config_name=None):
    if config_name is None:
        config_name = os.environ.get("FLASK_ENV", "development")
    app = Flask(__name__,
                template_folder=os.path.join(os.path.dirname(__file__), "templates"),
                static_folder=os.path.join(os.path.dirname(__file__), "static"))
    app.config.from_object(config_by_name[config_name])
    os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)

    db.init_app(app)
    login_manager.init_app(app)

    init_translations()

    register_blueprints(app)
    register_error_handlers(app)
    register_context_processors(app)
    register_pwa_routes(app)

    import json as _json
    @app.template_filter("fromjson")
    def _fromjson(value):
        try:
            return _json.loads(value)
        except Exception:
            return []

    with app.app_context():
        db.create_all()
        try:
            from app.models.support import ensure_support_columns
            ensure_support_columns()
        except Exception as _e:
            logger.warning(f"support migration skipped: {_e}")
        # Migration for site_background column
        try:
            from sqlalchemy import inspect, text
            inspector = inspect(db.engine)
            if "site_config" in inspector.get_table_names():
                existing = {c["name"] for c in inspector.get_columns("site_config")}
                if "site_background" not in existing:
                    with db.engine.begin() as conn:
                        conn.execute(text("ALTER TABLE site_config ADD COLUMN site_background VARCHAR(255)"))
        except Exception as _e:
            logger.warning(f"site_background migration skipped: {_e}")
        # Migration for notifications.icon column (rich admin messages)
        try:
            from sqlalchemy import inspect, text
            inspector = inspect(db.engine)
            if "notifications" in inspector.get_table_names():
                existing = {c["name"] for c in inspector.get_columns("notifications")}
                if "icon" not in existing:
                    with db.engine.begin() as conn:
                        conn.execute(text("ALTER TABLE notifications ADD COLUMN icon VARCHAR(16) DEFAULT '📢'"))
        except Exception as _e:
            logger.warning(f"notifications.icon migration skipped: {_e}")
        seed_database()
    return app


def register_blueprints(app):
    from app.blueprints.public import bp as public_bp
    from app.blueprints.auth import bp as auth_bp
    from app.blueprints.web import bp as web_bp
    from app.blueprints.admin import bp as admin_bp
    from app.blueprints.api import bp as api_bp
    from app.blueprints.dns import bp as dns_bp
    from app.blueprints.support import bp as support_bp

    app.register_blueprint(public_bp)
    app.register_blueprint(auth_bp, url_prefix="/auth")
    app.register_blueprint(web_bp)
    app.register_blueprint(admin_bp, url_prefix="/admin")
    app.register_blueprint(api_bp, url_prefix="/api")
    app.register_blueprint(dns_bp)
    app.register_blueprint(support_bp)


def register_pwa_routes(app):
    """PWA plumbing — manifest + service worker MUST be served from the
    root scope for the whole origin (a /static/ URL would limit the SW
    scope to /static/ and break installability)."""
    import os
    from flask import send_from_directory

    static_dir = app.static_folder

    @app.route("/sw.js")
    def service_worker():
        resp = send_from_directory(static_dir, "sw.js",
                                   mimetype="application/javascript")
        resp.headers["Service-Worker-Allowed"] = "/"
        # SW script must be revalidated on every load so updates ship fast
        resp.headers["Cache-Control"] = "no-cache"
        resp.headers["X-Content-Type-Options"] = "nosniff"
        return resp

    @app.route("/manifest.webmanifest")
    def webmanifest():
        resp = send_from_directory(static_dir, "manifest.webmanifest",
                                   mimetype="application/manifest+json")
        resp.headers["Cache-Control"] = "public, max-age=3600"
        return resp


def register_error_handlers(app):
    @app.errorhandler(404)
    def not_found(e):
        return render_template("errors/404.html"), 404

    @app.errorhandler(403)
    def forbidden(e):
        return render_template("errors/403.html"), 403

    @app.errorhandler(500)
    def server_error(e):
        return render_template("errors/500.html"), 500


def register_context_processors(app):
    @app.context_processor
    def inject_globals():
        from app.models.user import User
        from app.models.game import Game
        from app.models.wallet import Wallet
        from app.models.team import Team
        from app.models.match import Match
        t = get_translator()
        lang = session.get("lang", app.config["DEFAULT_LANG"])
        ticker_matches = []
        user_theme = session.get("theme", "dark")
        header_games = []
        entry_balance = 0
        header_teams = []
        recent_notifs = []
        unread_count = 0
        user_region_code = session.get("region", "global")
        if "user_id" in session:
            try:
                user = db.session.get(User, session["user_id"])
                if user:
                    user_theme = user.theme or "dark"
                    if user.region:
                        user_region_code = user.region
                    header_games = (Game.query.filter_by(is_active=True)
                                    .order_by(Game.sort_order).all())
                    header_teams = (Team.query.filter_by(owner_id=user.id)
                                    .order_by(Team.created_at.desc()).all())
                    ew = Wallet.query.filter_by(user_id=user.id, kind="deposit").first()
                    entry_balance = ew.balance if ew else 0
                    from app.models.notification import Notification
                    recent_notifs = (Notification.query
                                     .filter_by(user_id=user.id, read=False)
                                     .order_by(Notification.created_at.desc())
                                     .limit(8)
                                     .all())
                    unread_count = (Notification.query
                                    .filter_by(user_id=user.id, read=False)
                                    .count())
                    ticker_matches = (Match.query
                        .filter(Match.status.in_(["live", "finished", "upcoming"]))
                        .order_by(Match.starts_at.desc())
                        .limit(15)
                        .all())
            except Exception as e:
                import logging
                logging.getLogger("app").exception("inject_globals error: %s", e)
        # Social media & site config
        socials = []
        site_logo = None
        site_name = "FIGHTSKILL"
        try:
            from app.models.social import SocialMedia
            from app.models.verification import AppSetting
            socials = SocialMedia.query.filter_by(is_active=True).order_by(SocialMedia.display_order).all()
            logo_setting = AppSetting.query.filter_by(key="site_logo").first()
            if logo_setting and logo_setting.value:
                site_logo = logo_setting.value
            name_setting = AppSetting.query.filter_by(key="site_name").first()
            if name_setting and name_setting.value:
                site_name = name_setting.value
        except Exception:
            pass
        return dict(
            t=t,
            current_lang=lang,
            is_rtl=lang in RTL_LANGS,
            rtl_langs=RTL_LANGS,
            config=app.config,
             upload_url=lambda fname: f"/static/uploads/{fname}" if fname else None,
             sv=lambda fn: __import__('flask').url_for('static', filename=fn, v=app.config.get('ASSET_VERSION', '1')),
            ticker_matches=ticker_matches,
            current_theme=user_theme,
            header_games=header_games,
            header_teams=header_teams,
            entry_balance=entry_balance,
            recent_notifs=recent_notifs,
            unread_count=unread_count,
            current_region=user_region_code,
            now=__import__('datetime').datetime.now(),
            socials=socials,
            site_logo=site_logo,
            site_name=site_name,
        )

    @app.before_request
    def set_i18n():
        g.lang = session.get("lang", app.config["DEFAULT_LANG"])
        g.t = get_translator(g.lang)
        request.i18n_lang = g.lang
        request.i18n = g.t


def seed_database():
    from app.models.region import Region
    from app.models.game import Game, GameMode
    from app.models.user import User, Role, Permission
    from app.models.verification import AppSetting
    from app.extensions import db

    if Region.query.count() == 0:
        regions = [
            ("global", "Global", "en,tr,fa,ar,ru", "🌍"),
            ("ir", "Iran", "fa,en", "🇮🇷"),
            ("tr", "Turkey", "tr,en", "🇹🇷"),
            ("eu", "Europe", "en,de,fr,es", "🇪🇺"),
            ("na", "North America", "en,es", "🇺🇸"),
            ("sa", "South America", "pt,es", "🇧🇷"),
            ("sea", "Southeast Asia", "en,id,vi", "🌏"),
            ("ea", "East Asia", "en,zh,ja,ko", "🌏"),
            ("mena", "MENA", "ar,en,fa", "🌍"),
            ("ru", "Russia", "ru,en", "🇷🇺"),
        ]
        for code, name, langs, flag in regions:
            db.session.add(Region(code=code, name=name, languages=langs, flag=flag))

    if Role.query.count() == 0:
        roles_data = [
            ("superadmin", "Super Admin", "manage_users,manage_games,manage_matches,manage_teams,manage_wallets,manage_settings,view_analytics,tournament_manage"),
            ("admin", "Admin", "manage_users,manage_games,manage_matches,manage_teams,manage_wallets,manage_settings,view_analytics,tournament_manage"),
            ("tournament_manager", "Tournament Manager", "manage_matches,tournament_manage"),
            ("moderator", "Moderator", "view_analytics"),
            ("user", "User", ""),
        ]
        for code, name, perms in roles_data:
            role = Role(code=code, name=name)
            db.session.add(role)
        db.session.commit()
        # assign permissions
        perm_codes = ["manage_users", "manage_games", "manage_matches", "manage_teams",
                      "manage_wallets", "manage_settings", "view_analytics", "tournament_manage"]
        for code in perm_codes:
            db.session.add(Permission(code=code, label=code))
        db.session.commit()
        admin_role = Role.query.filter_by(code="admin").first()
        super_role = Role.query.filter_by(code="superadmin").first()
        tm_role = Role.query.filter_by(code="tournament_manager").first()
        all_perms = Permission.query.all()
        if admin_role:
            admin_role.permissions = [p for p in all_perms if p.code in ("manage_users","manage_games","manage_matches","manage_teams","manage_wallets","manage_settings","view_analytics","tournament_manage")]
        if super_role:
            super_role.permissions = all_perms
        if tm_role:
            tm_role.permissions = [p for p in all_perms if p.code in ("manage_matches","tournament_manage")]
        db.session.commit()

    if Game.query.count() == 0:
        games_data = [
            ("cs2", "Counter-Strike 2", "🔫"),
            ("valorant", "Valorant", "⚔️"),
            ("codm", "Call of Duty Mobile", "🎯"),
            ("pubgm", "PUBG Mobile", "🪖"),
            ("freefire", "Free Fire", "🔥"),
            ("efootball", "eFootball", "⚽"),
            ("lol", "League of Legends", "🏆"),
            ("dota2", "Dota 2", "🛡️"),
        ]
        for slug, name, icon in games_data:
            # Real game artwork bundled locally (app/static/img/games/<slug>.jpg)
            img = f"/static/img/games/{slug}.jpg"
            db.session.add(Game(slug=slug, name=name, icon=icon,
                                sort_order=len(games_data) - games_data.index((slug, name, icon)),
                                image=img))
        db.session.flush()
        # add modes for first few games
        cs = Game.query.filter_by(slug="cs2").first()
        val = Game.query.filter_by(slug="valorant").first()
        cod = Game.query.filter_by(slug="codm").first()
        if cs:
            for s, n, sq in [("competitive", "Competitive 5v5", 5), ("wingman", "Wingman 2v2", 2)]:
                db.session.add(GameMode(game_id=cs.id, slug=s, name=n, squad_size=sq))
        if val:
            for s, n, sq in [("unrated", "Unrated 5v5", 5), ("ranked", "Ranked", 5)]:
                db.session.add(GameMode(game_id=val.id, slug=s, name=n, squad_size=sq))
        if cod:
            for s, n, sq in [("multi-battle", "Multi Battle", 4), ("br", "Battle Royale", 4)]:
                db.session.add(GameMode(game_id=cod.id, slug=s, name=n, squad_size=sq))

    if User.query.filter_by(email="admin@vapolyx.gg").first() is None:
        admin = User(
            email="admin@vapolyx.gg",
            username="admin",
            role_id=Role.query.filter_by(code="superadmin").first().id,
            lang="fa",
            theme="dark",
        )
        admin.set_password("Admin@123")
        admin.email_verified = True
        admin.intro_seen = True
        db.session.add(admin)

    # Seed social media links
    from app.models.social import SocialMedia
    if SocialMedia.query.count() == 0:
        socials_data = [
            ("Discord", "💬", "https://discord.gg/fightskill", 1),
            ("Telegram", "✈️", "https://t.me/fightskill", 2),
            ("Instagram", "📷", "https://instagram.com/fightskill", 3),
            ("Twitter", "🐦", "https://twitter.com/fightskill", 4),
            ("YouTube", "▶️", "https://youtube.com/@fightskill", 5),
        ]
        for name, icon, url, order in socials_data:
            db.session.add(SocialMedia(name=name, icon=icon, url=url, display_order=order, is_active=True))

    db.session.commit()
