"""
Employee Workstation Activity Tracking - Flask Application Factory

This module provides the application factory function 'create_app' that initializes 
the Flask application with its configuration, database connection, and registered blueprints.
"""
import logging
import os
from logging.handlers import RotatingFileHandler

from dotenv import load_dotenv
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import event

# Initialize SQLAlchemy globally to avoid circular imports
db = SQLAlchemy()


def create_app(test_config=None):
    """Create and configure the Flask application using the factory pattern."""

    # Load environment variables
    load_dotenv()  # Try .env first
    config_env_path = os.path.join(
        os.path.dirname(os.path.dirname(__file__)), "config.env"
    )
    # Defer logging for config.env until logger is configured
    config_env_loaded_message = None
    config_env_warning_message = None
    if os.path.exists(config_env_path):
        load_dotenv(config_env_path)
        config_env_loaded_message = (
            f"Loaded environment variables from {config_env_path}"
        )
    else:
        config_env_warning_message = (
            f"Warning: config.env file not found at {config_env_path}"
        )

    # Get the project root directory (parent of app directory)
    project_root = os.path.dirname(os.path.dirname(__file__))

    # Create and configure the app with template folder in project root
    app = Flask(
        __name__,
        instance_relative_config=True,
        template_folder=os.path.join(project_root, "templates"),
        static_folder=os.path.join(project_root, "static"),
    )

    # Default configuration
    app.config.from_mapping(
        SECRET_KEY=os.environ.get("SECRET_KEY", "dev"),
        SQLALCHEMY_DATABASE_URI=os.environ.get(
            "DATABASE_URI", os.environ.get("DATABASE_URL")
        ),
        SQLALCHEMY_TRACK_MODIFICATIONS=False,
    )

    # Override configuration with test config if provided
    if test_config is not None:
        app.config.update(test_config)

    # Ensure DATABASE_URI is set
    if not app.config["SQLALCHEMY_DATABASE_URI"]:
        raise ValueError(
            "DATABASE_URI or DATABASE_URL environment variable must be set"
        )

    # Ensure the instance folder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    # Configure logging
    if not app.debug:  # Avoid duplicate logs in debug mode
        log_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
        log_handler = RotatingFileHandler(
            os.path.join(app.instance_path, "server.log"),
            maxBytes=1024 * 1024 * 5,  # 5 MB
            backupCount=5,
        )
        log_handler.setFormatter(log_formatter)
        log_handler.setLevel(logging.INFO)
        app.logger.addHandler(log_handler)
        app.logger.setLevel(logging.INFO)

    # Log config.env messages now that logger is available
    if config_env_loaded_message:
        app.logger.info(config_env_loaded_message)
    if config_env_warning_message:
        app.logger.warning(config_env_warning_message)

    app.logger.info("Flask application starting up...")

    # Initialize the database with the app
    db.init_app(app)

    # Set up event listener for PostgreSQL timezone
    with app.app_context():
        if "postgresql" in app.config["SQLALCHEMY_DATABASE_URI"]:

            @event.listens_for(db.engine, "connect")
            def set_timezone(dbapi_connection, connection_record):
                cursor = dbapi_connection.cursor()
                cursor.execute("SET timezone TO 'Asia/Dubai';")
                cursor.close()
                app.logger.info("Set PostgreSQL session timezone to 'Asia/Dubai' (UTC+4)")
                app.logger.info("Note: Application uses UTC internally, database is set to Asia/Dubai time.")

    # Import and register blueprints
    from app.api import events_bp, reports_bp

    app.register_blueprint(events_bp)
    app.register_blueprint(reports_bp)

    from app.views.dashboard import views_bp

    app.register_blueprint(views_bp)

    # Register error handlers
    from app.errors import register_error_handlers

    register_error_handlers(app)

    # Initialize database tables when in development
    @app.cli.command("init-db")
    def init_db_command():
        """Clear existing data and create new tables."""
        with app.app_context():
            db.create_all()
            app.logger.info("Database tables created")

    @app.route("/healthcheck")
    def healthcheck():
        return {"status": "ok"}, 200

    # Initialize and start the scheduler
    from app.scheduler import init_scheduler
    init_scheduler(app)

    # Register custom CLI commands
    from app.cli import register_cli_commands
    register_cli_commands(app)

    return app


def init_db(app_instance):
    """Initialize the database outside of the CLI context using a provided app
    instance."""
    # app = create_app() # No longer creating app here, using provided instance
    with app_instance.app_context():
        db.create_all()
        app_instance.logger.info("Database initialized via init_db function")
