"""Flask application factory."""

import os
from pathlib import Path

from flask import Flask
from flask_migrate import Migrate

from .database import db


def create_app(config=None):
    """Create and configure Flask application.

    Args:
        config: Optional configuration dictionary to override defaults

    Returns:
        Configured Flask application instance
    """
    # Determine paths
    # DB_PATH env var sets the SQLite file location (useful for Docker volume mounts).
    # Defaults to <repo-root>/instance/words_to_readlang.db for local development.
    db_path = os.environ.get("DB_PATH")
    if db_path:
        instance_path = Path(db_path).parent
    else:
        instance_path = Path(__file__).parent.parent.parent.parent / "instance"
    instance_path.mkdir(parents=True, exist_ok=True)

    db_file = Path(db_path) if db_path else instance_path / "words_to_readlang.db"

    app = Flask(
        __name__,
        template_folder=str(Path(__file__).parent / "templates"),
        static_folder=str(Path(__file__).parent / "static"),
        instance_path=str(instance_path),
    )

    # Default configuration
    app.config.update(
        {
            "SQLALCHEMY_DATABASE_URI": f"sqlite:///{db_file}",
            "SQLALCHEMY_TRACK_MODIFICATIONS": False,
            "SECRET_KEY": os.environ.get("SECRET_KEY", "dev-secret-key-change-in-production"),
            "MAX_CONTENT_LENGTH": 10 * 1024 * 1024,  # 10MB max upload
        }
    )

    # Override with custom config if provided
    if config:
        app.config.update(config)

    # Initialize database
    db.init_app(app)

    # Initialize migrations
    migrate = Migrate(app, db)

    # Create tables (for initial setup only, migrations handle schema changes)
    with app.app_context():
        from . import models  # noqa: F401

        db.create_all()

    # Register blueprints
    register_blueprints(app)

    # Register error handlers
    register_error_handlers(app)

    # Register context processor to make g.session available in templates
    @app.context_processor
    def inject_session():
        from flask import g
        return {"user_session": getattr(g, "session", None)}

    # Register template filters
    from .utils.languages import get_language_name, format_language_pair

    @app.template_filter('language_name')
    def language_name_filter(code):
        """Template filter to convert language code to name."""
        return get_language_name(code)

    @app.template_filter('language_pair')
    def language_pair_filter(upload):
        """Template filter to format upload's language pair."""
        return format_language_pair(upload.source_language, upload.target_language)

    # Add cache headers for static files
    @app.after_request
    def add_cache_headers(response):
        """Add cache headers for static files to prevent logo flashing."""
        from flask import request

        # Cache static files for 1 hour, even in debug mode
        if request.path.startswith('/static/'):
            response.cache_control.max_age = 3600
            response.cache_control.public = True

        return response

    # Register CLI commands
    register_commands(app)

    return app


def register_commands(app):
    """Register Flask CLI commands."""
    import click

    @app.cli.command("purge-expired")
    def purge_expired():
        """Delete sessions (and their uploads/entries) that have expired."""
        from datetime import datetime
        from .models import Session

        now = datetime.utcnow()
        expired = Session.query.filter(Session.expires_at < now).all()
        count = len(expired)
        for session in expired:
            db.session.delete(session)
        db.session.commit()
        click.echo(f"Deleted {count} expired session(s).")


def register_blueprints(app):
    """Register Flask blueprints.

    Args:
        app: Flask application instance
    """
    from .routes.main import main_bp
    from .routes.upload import upload_bp
    from .routes.preview import preview_bp
    from .routes.validate import validate_bp
    from .routes.edit import edit_bp
    from .routes.tatoeba import tatoeba_bp
    from .routes.export import export_bp
    from .routes.pool import pool_bp

    app.register_blueprint(main_bp)
    app.register_blueprint(upload_bp, url_prefix="/upload")
    app.register_blueprint(preview_bp, url_prefix="/preview")
    app.register_blueprint(validate_bp, url_prefix="/validate")
    app.register_blueprint(edit_bp, url_prefix="/edit")
    app.register_blueprint(tatoeba_bp, url_prefix="/tatoeba")
    app.register_blueprint(export_bp, url_prefix="/export")
    app.register_blueprint(pool_bp, url_prefix="/pool")


def register_error_handlers(app):
    """Register error handlers.

    Args:
        app: Flask application instance
    """

    @app.errorhandler(404)
    def not_found(error):
        return {"error": "Not found"}, 404

    @app.errorhandler(500)
    def internal_error(error):
        db.session.rollback()
        return {"error": "Internal server error"}, 500

    @app.errorhandler(413)
    def request_entity_too_large(error):
        return {"error": "File too large (max 10MB)"}, 413
