from flask import Flask, render_template, redirect, url_for, request
from flask_login import current_user
from app.config import Config
from app.extensions import db, migrate, login_manager, csrf, limiter, mail


def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)

    db.init_app(app)
    migrate.init_app(app, db)
    login_manager.init_app(app)
    csrf.init_app(app)
    limiter.init_app(app)
    mail.init_app(app)

    from app.models import User, Plan, Subscription, Report  # noqa: F401
    from app.models.report import ReportNotebook, NotebookAsset  # noqa: F401
    from app.models.features import (BackgroundTask, WebhookEndpoint, Workspace,  # noqa: F401
        WorkspaceMember, ReportTemplate, AuditLog, Referral, ChatMessage,
        CompetitorMonitor, InvestorContact, MarketplaceListing, MarketplacePurchase,
        MarketplaceInquiry, MarketplaceReview,
        WhiteLabelConfig, Grant, CoFounderProfile, ReportVersion,
        Notification, SearchIndex,
        ActivityLog, KanbanCard, LegalDocument, SystemPrompt, VideoProviderConfig)
    from app.models.ads import (AdminAdAccount, AdBudgetWallet, UserAdBudget,  # noqa: F401
        AdCampaign, AdCampaignMetrics, AdAuditLog)
    from app.models.services import (FactoryPartner, PrototypeRequest,  # noqa: F401
        PrototypeQuote, PrototypeMessage, PatentApplication, TrademarkApplication)

    from app.routes.auth import auth_bp
    from app.routes.dashboard import dashboard_bp
    from app.routes.study import study_bp
    from app.routes.billing import billing_bp
    from app.routes.admin import admin_bp
    from app.routes.campaigns import campaigns_bp
    from app.routes.websites import websites_bp
    from app.routes.intelligence import intelligence_bp
    from app.routes.gamma import gamma_bp
    from app.routes.company import company_bp
    from app.routes.incubator import incubator_bp
    from app.routes.tools import tools_bp
    from app.routes.api_marketplace import api_bp
    from app.routes.tasks import tasks_bp
    from app.routes.workspaces import workspaces_bp
    from app.routes.report_templates import templates_bp
    from app.routes.referral import referral_bp
    from app.routes.audit import audit_bp
    from app.routes.chatbot import chatbot_bp
    from app.routes.marketplace import marketplace_bp
    from app.routes.investor_crm import investor_crm_bp
    from app.routes.grants import grants_bp
    from app.routes.cofounders import cofounders_bp
    from app.routes.advanced import advanced_bp
    from app.routes.notifications import notifications_bp
    from app.routes.search import search_bp
    from app.routes.whitelabel import whitelabel_bp
    from app.routes.kanban import kanban_bp
    from app.routes.legal import legal_bp
    from app.routes.integrations import integrations_bp
    from app.routes.roadmap import roadmap_bp
    from app.routes.kpis import kpis_bp
    from app.routes.advisor import advisor_bp
    from app.routes.market_monitor import market_bp
    from app.routes.prototyping import prototyping_bp
    from app.routes.ip import ip_bp

    app.register_blueprint(auth_bp)
    app.register_blueprint(dashboard_bp)
    app.register_blueprint(study_bp)
    app.register_blueprint(billing_bp)
    app.register_blueprint(admin_bp)
    app.register_blueprint(campaigns_bp)
    app.register_blueprint(websites_bp)
    app.register_blueprint(intelligence_bp)
    app.register_blueprint(gamma_bp)
    app.register_blueprint(company_bp)
    app.register_blueprint(incubator_bp)
    app.register_blueprint(tools_bp)
    app.register_blueprint(api_bp)
    app.register_blueprint(tasks_bp)
    app.register_blueprint(workspaces_bp)
    app.register_blueprint(templates_bp)
    app.register_blueprint(referral_bp)
    app.register_blueprint(audit_bp)
    app.register_blueprint(chatbot_bp)
    app.register_blueprint(marketplace_bp)
    app.register_blueprint(investor_crm_bp)
    app.register_blueprint(grants_bp)
    app.register_blueprint(cofounders_bp)
    app.register_blueprint(advanced_bp)
    app.register_blueprint(notifications_bp)
    app.register_blueprint(search_bp)
    app.register_blueprint(whitelabel_bp)
    app.register_blueprint(kanban_bp)
    app.register_blueprint(legal_bp)
    app.register_blueprint(integrations_bp)
    app.register_blueprint(roadmap_bp)
    app.register_blueprint(kpis_bp)
    app.register_blueprint(advisor_bp)
    app.register_blueprint(market_bp)
    app.register_blueprint(prototyping_bp)
    app.register_blueprint(ip_bp)

    from app.i18n import init_i18n
    init_i18n(app)

    @app.context_processor
    def inject_globals():
        if current_user.is_authenticated:
            from app.models.features import Notification
            unread = Notification.query.filter_by(user_id=current_user.id, is_read=False).count()
            return {"unread_notifications": unread}
        return {"unread_notifications": 0}

    @app.route("/set-language/<lang>")
    def set_language(lang):
        from flask import session
        if lang not in ("ar", "en"):
            lang = "ar"
        session["lang"] = lang
        if current_user.is_authenticated:
            current_user.language_pref = lang
            db.session.commit()
        next_url = request.args.get("next") or request.referrer or url_for("landing")
        return redirect(next_url)

    @app.route("/")
    def landing():
        if current_user.is_authenticated:
            return redirect(url_for("dashboard.index"))
        return render_template("landing.html")

    @app.route("/marketing/brochure")
    def marketing_brochure():
        return render_template("marketing/brochure.html")

    @app.errorhandler(404)
    def not_found(e):
        return render_template("errors/404.html"), 404

    @app.errorhandler(500)
    def server_error(e):
        return render_template("errors/500.html"), 500

    @app.errorhandler(429)
    def too_many_requests(e):
        return render_template("errors/429.html"), 429

    @app.route("/sitemap.xml")
    def sitemap():
        from flask import Response
        pages = ["landing", "auth.login", "auth.register", "billing.plans"]
        xml = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
        for p in pages:
            try:
                loc = url_for(p, _external=True)
                xml += f'  <url><loc>{loc}</loc><changefreq>weekly</changefreq><priority>0.8</priority></url>\n'
            except Exception:
                pass
        xml += '</urlset>'
        return Response(xml, mimetype='application/xml')

    @app.route("/robots.txt")
    def robots():
        from flask import Response
        txt = f"User-agent: *\nAllow: /\nSitemap: {url_for('sitemap', _external=True)}\nDisallow: /dashboard\nDisallow: /admin\nDisallow: /api"
        return Response(txt, mimetype='text/plain')

    @app.after_request
    def add_cache_headers(resp):
        if 'static' in request.path:
            resp.headers['Cache-Control'] = 'public, max-age=604800'
        return resp

    with app.app_context():
        db.create_all()
        _safe_migrate(db)
        _seed_plans()
        _seed_admin()

    return app


def _seed_plans():
    from app.models.subscription import Plan as PlanModel
    try:
        if PlanModel.query.first() is not None:
            return
    except Exception:
        db.create_all()
    if PlanModel.query.first() is not None:
        return
    plans = [
        PlanModel(
            name="free", display_name="Free",
            reports_per_month=2, price_monthly=0,
            can_export_pdf=False, has_api_access=False,
        ),
        PlanModel(
            name="pro", display_name="Pro",
            reports_per_month=50, price_monthly=29,
            stripe_price_id=Config.STRIPE_PRICE_PRO,
            can_export_pdf=True, has_api_access=False,
        ),
        PlanModel(
            name="enterprise", display_name="Enterprise",
            reports_per_month=-1, price_monthly=99,
            stripe_price_id=Config.STRIPE_PRICE_ENTERPRISE,
            can_export_pdf=True, has_api_access=True,
        ),
        PlanModel(
            name="empire", display_name="Empire",
            reports_per_month=-1, price_monthly=299,
            can_export_pdf=True, has_api_access=True,
        ),
    ]
    db.session.add_all(plans)
    db.session.commit()


def _safe_migrate(database):
    """Add new columns to existing tables if they don't exist (no migration system)."""
    from sqlalchemy import inspect, text
    inspector = inspect(database.engine)
    # Add video_provider to users table
    if "users" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("users")]
        if "video_provider" not in cols:
            database.session.execute(text("ALTER TABLE users ADD COLUMN video_provider VARCHAR(20)"))
            database.session.commit()
    # Add NotebookLM session fields to users table
    if "users" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("users")]
        if "google_nlm_session_path" not in cols:
            database.session.execute(text("ALTER TABLE users ADD COLUMN google_nlm_session_path VARCHAR(500)"))
            database.session.commit()
        if "google_nlm_connected_at" not in cols:
            database.session.execute(text("ALTER TABLE users ADD COLUMN google_nlm_connected_at TIMESTAMP"))
            database.session.commit()
    # Add video_provider to plans table
    if "plans" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("plans")]
        if "video_provider" not in cols:
            database.session.execute(text("ALTER TABLE plans ADD COLUMN video_provider VARCHAR(20) DEFAULT 'sora'"))
            database.session.commit()
    # Add video_duration and user_script_notes to campaigns table
    if "campaigns" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("campaigns")]
        if "video_duration" not in cols:
            database.session.execute(text("ALTER TABLE campaigns ADD COLUMN video_duration INTEGER"))
            database.session.commit()
        if "user_script_notes" not in cols:
            database.session.execute(text("ALTER TABLE campaigns ADD COLUMN user_script_notes TEXT"))
            database.session.commit()
    # Add publish_mode to campaign_posts table
    if "campaign_posts" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("campaign_posts")]
        if "publish_mode" not in cols:
            database.session.execute(text("ALTER TABLE campaign_posts ADD COLUMN publish_mode VARCHAR(20) DEFAULT 'my_accounts'"))
            database.session.commit()
    # Marketplace listing new columns
    if "marketplace_listings" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("marketplace_listings")]
        new_cols = {
            "listing_goal": "VARCHAR(30) DEFAULT 'sell'",
            "title": "VARCHAR(500)",
            "sector": "VARCHAR(100)",
            "preview_text": "TEXT",
            "investment_needed": "FLOAT",
            "equity_offered": "FLOAT",
            "partner_role": "VARCHAR(500)",
            "license_terms": "TEXT",
            "contact_email": "VARCHAR(255)",
            "cover_image": "VARCHAR(500)",
            "approval_status": "VARCHAR(20) DEFAULT 'approved'",
            "admin_notes": "TEXT",
            "featured": "BOOLEAN DEFAULT FALSE",
        }
        for col_name, col_type in new_cols.items():
            if col_name not in cols:
                try:
                    database.session.execute(text(f"ALTER TABLE marketplace_listings ADD COLUMN {col_name} {col_type}"))
                    database.session.commit()
                except Exception:
                    database.session.rollback()
    # User role/account type fields
    if "users" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("users")]
        user_new_cols = {
            "account_type": "VARCHAR(30) DEFAULT 'entrepreneur'",
            "interests_json": "JSON",
            "company_name": "VARCHAR(500)",
            "factory_partner_id": "INTEGER REFERENCES factory_partners(id)",
        }
        for col_name, col_type in user_new_cols.items():
            if col_name not in cols:
                try:
                    database.session.execute(text(f"ALTER TABLE users ADD COLUMN {col_name} {col_type}"))
                    database.session.commit()
                except Exception:
                    database.session.rollback()
    # FactoryPartner user_id field
    if "factory_partners" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("factory_partners")]
        if "user_id" not in cols:
            try:
                database.session.execute(text("ALTER TABLE factory_partners ADD COLUMN user_id INTEGER REFERENCES users(id)"))
                database.session.commit()
            except Exception:
                database.session.rollback()
    # PrototypeRequest NDA and cost estimate fields
    if "prototype_requests" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("prototype_requests")]
        proto_new_cols = {
            "nda_html": "TEXT",
            "nda_status": "VARCHAR(30)",
            "nda_generated_at": "TIMESTAMP",
            "nda_approved_at": "TIMESTAMP",
            "cost_estimate_json": "JSON",
            "cost_estimate_generated_at": "TIMESTAMP",
        }
        for col_name, col_type in proto_new_cols.items():
            if col_name not in cols:
                try:
                    database.session.execute(text(f"ALTER TABLE prototype_requests ADD COLUMN {col_name} {col_type}"))
                    database.session.commit()
                except Exception:
                    database.session.rollback()
    # Marketplace purchase new columns
    if "marketplace_purchases" in inspector.get_table_names():
        cols = [c["name"] for c in inspector.get_columns("marketplace_purchases")]
        purchase_cols = {
            "stripe_session_id": "VARCHAR(255)",
            "stripe_payment_intent": "VARCHAR(255)",
            "status": "VARCHAR(20) DEFAULT 'completed'",
            "currency": "VARCHAR(10) DEFAULT 'USD'",
        }
        for col_name, col_type in purchase_cols.items():
            if col_name not in cols:
                try:
                    database.session.execute(text(f"ALTER TABLE marketplace_purchases ADD COLUMN {col_name} {col_type}"))
                    database.session.commit()
                except Exception:
                    database.session.rollback()


def _seed_admin():
    from app.models.user import User as UserModel
    admin_email = Config.ADMIN_EMAIL
    if not admin_email:
        return
    user = UserModel.query.filter_by(email=admin_email).first()
    if user and not user.is_admin:
        user.is_admin = True
        db.session.commit()
