"""Main Flask application for the Fellowship Quest Tracker."""
from dotenv import load_dotenv
import os

# Load environment variables from .env file (if present)
# This must happen before any config is loaded
load_dotenv()

from flask import Flask, jsonify, request, session
from flask_cors import CORS
from flask_restx import Api
from config import config
from models.user import db
from utils.database import init_db
from utils.seed_data import seed_database
from routes.auth import auth_bp, auth_api
from routes.quests import quests_bp, quests_api
from routes.members import members_bp, members_api
from routes.locations import locations_bp, locations_api
from routes.npc_chat import npc_chat_bp, npc_chat_api
from routes.shop import shop_bp, shop_api
from services.shop_service import ShopService
from datetime import datetime, timezone, timedelta
from typing import Optional


APP_STARTED_AT_UTC = datetime.now(timezone.utc)


def _read_uptime_seconds() -> Optional[float]:
    try:
        with open('/proc/uptime', 'r', encoding='utf-8') as uptime_file:
            first_field = uptime_file.read().split()[0]
            return float(first_field)
    except (OSError, ValueError, IndexError):
        return None


def _instance_boot_time_utc() -> Optional[datetime]:
    uptime_seconds = _read_uptime_seconds()
    if uptime_seconds is None:
        return None
    return datetime.now(timezone.utc) - timedelta(seconds=uptime_seconds)

def create_app(config_name: str = None) -> Flask:
    """Create and configure Flask application."""
    app = Flask(__name__)
    
    # Load configuration
    config_name = config_name or os.environ.get('FLASK_ENV', 'development')
    app.config.from_object(config[config_name])
    
    # Configure session
    app.config['SESSION_COOKIE_HTTPONLY'] = True
    app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'  # Allows cross-site cookies for development
    app.config['SESSION_COOKIE_SECURE'] = False  # Set to True in production with HTTPS
    
    # Initialize CORS with specific origins (required when using credentials)
    # Allow both localhost:3000 (dev) and localhost (production via nginx)
    # Flask-CORS handles preflight OPTIONS requests automatically
    CORS(
        app,
        supports_credentials=True,
        resources={
            r"/api/*": {
                "origins": [
                    "http://localhost:3000",
                    "http://localhost",
                    "http://127.0.0.1:3000",
                    "http://127.0.0.1",
                ]
            }
        },
        allow_headers=["Content-Type", "Authorization"],
        methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    )
    
    # Initialize database (this also initializes db)
    init_db(app)
    
    # Seed database with initial data
        # Skip seeding in test mode
    # Skip seeding in test mode
    if not app.config.get("TESTING") and not os.environ.get("TESTING"):
        seed_database(app)
    # Create main API with Swagger documentation
    api = Api(
        app,
        version='1.0',
        title='The Fellowship\'s Quest List API',
        description='REST API for tracking the Fellowship\'s epic journey through Middle-earth',
        doc='/api/swagger/',
        prefix='/api'
    )
    
    # Register blueprints (this registers both the blueprints and their Flask-RESTX routes)
    # Flask-RESTX Api objects bound to blueprints automatically register routes when blueprint is registered
    app.register_blueprint(auth_bp)
    app.register_blueprint(quests_bp)
    app.register_blueprint(members_bp)
    app.register_blueprint(locations_bp)
    app.register_blueprint(npc_chat_bp)
    app.register_blueprint(shop_bp)
    
    # Note: We don't add the Api objects as namespaces because they're already bound to blueprints
    # Adding them as namespaces would cause route conflicts. The routes work from blueprints alone.
    # For Swagger, each Api has its own documentation, but we can add them to the main API if needed.
    # However, this requires creating Namespace objects, not using the Api objects directly.
    
    # Health check endpoint
    @app.route('/api/health')
    def health():
        """Health check endpoint."""
        return jsonify({'status': 'healthy', 'service': 'fellowship-quest-tracker'}), 200

    # Test cleanup endpoint (development only - deletes accumulated test data)
    @app.route('/api/test/cleanup', methods=['POST'])
    def test_cleanup():
        """Delete quests created during e2e test runs to prevent database bloat."""
        from models.quest import Quest as QuestModel
        # Only allowed in non-production environments
        if app.config.get('ENV') == 'production':
            return jsonify({'error': 'Not available in production'}), 403
        test_patterns = [
            'BDD', 'Test Quest', 'Find the One Ring', 'Explore Rivendell',
            'Defeat Sauron', 'Completed Quest', 'In Progress Quest',
            'Journey Quest', 'Battle Quest', 'Ring Quest',
            'Mordor Quest', 'Rivendell Quest', 'Dark Magic Quest',
            'Mini-game Quest',
        ]
        deleted = 0
        try:
            for pattern in test_patterns:
                quests = QuestModel.query.filter(QuestModel.title.contains(pattern)).all()
                for q in quests:
                    db.session.delete(q)
                    deleted += 1
            db.session.commit()
            return jsonify({'deleted': deleted, 'status': 'ok'}), 200
        except Exception as e:
            db.session.rollback()
            return jsonify({'error': str(e)}), 500

    @app.route('/api/test/set_gold', methods=['POST'])
    def test_set_gold():
        """Set the current user's gold balance (for e2e testing only)."""
        if app.config.get('ENV') == 'production':
            return jsonify({'error': 'Not available in production'}), 403
        from models.user import User as UserModel
        user_id = session.get('user_id')
        if not user_id:
            return jsonify({'error': 'Not authenticated'}), 401
        data = request.get_json() or {}
        gold = data.get('gold')
        if gold is None or not isinstance(gold, int) or gold < 0:
            return jsonify({'error': 'gold must be a non-negative integer'}), 400
        try:
            user = UserModel.query.get(user_id)
            if not user:
                return jsonify({'error': 'User not found'}), 404
            user.gold = gold
            db.session.commit()
            return jsonify({'gold': user.gold, 'status': 'ok'}), 200
        except Exception as e:
            db.session.rollback()
            return jsonify({'error': str(e)}), 500

    @app.route('/api/test/reset_shop', methods=['POST'])
    def test_reset_shop():
        """Reset all items to not-sold and clear inventory for e2e testing."""
        if app.config.get('ENV') == 'production':
            return jsonify({'error': 'Not available in production'}), 403
        try:
            result = ShopService.reset_for_tests()
            return jsonify(result), 200
        except Exception as e:
            return jsonify({'error': str(e)}), 500

    @app.route('/api/status')
    def status():
        """Runtime status endpoint exposed for public uptime/restart information."""
        instance_boot_time = _instance_boot_time_utc()
        payload = {
            'status': 'ok',
            'service': 'fellowship-quest-tracker',
            'app_started_at_utc': APP_STARTED_AT_UTC.isoformat(),
            'instance_boot_time_utc': instance_boot_time.isoformat() if instance_boot_time else None,
            'now_utc': datetime.now(timezone.utc).isoformat(),
        }
        return jsonify(payload), 200
    
    # API info endpoint (instead of root, since nginx handles root routing)
    @app.route('/api')
    def api_info():
        """API information endpoint."""
        return jsonify({
            'message': 'Welcome to The Fellowship\'s Quest List API',
            'version': '1.0',
            'docs': '/api/swagger/',
            'health': '/api/health',
            'status': '/api/status'
        }), 200
    
    # Debug endpoint to list all registered routes (development only)
    if app.config.get('DEBUG'):
        @app.route('/api/routes')
        def list_routes():
            """List all registered routes (debug endpoint)."""
            routes = []
            for rule in app.url_map.iter_rules():
                if rule.rule.startswith('/api'):
                    routes.append({
                        'endpoint': rule.endpoint,
                        'methods': list(rule.methods - {'HEAD', 'OPTIONS'}),
                        'path': str(rule)
                    })
            return jsonify({'routes': sorted(routes, key=lambda x: x['path'])}), 200
    
    return app

if __name__ == '__main__':
    try:
        app = create_app()
        app.run(host='0.0.0.0', port=5000, debug=True)
    except Exception as e:
        import traceback
        print(f"Error starting application: {e}")
        traceback.print_exc()
        raise