from flask import Flask, jsonify, request, send_from_directory, session
from flask_cors import CORS
from flask_session import Session
from dotenv import load_dotenv
import os
import sys
import logging
import uuid
from datetime import datetime, timedelta
from werkzeug.utils import secure_filename
from functools import wraps

# Load environment variables
load_dotenv()

# Untuk cPanel Passenger, tambahkan path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = None
        auth_header = request.headers.get('Authorization')
        
        if auth_header and auth_header.startswith('Bearer '):
            token = auth_header.split(' ')[1]
        
        if not token:
            return jsonify({'success': False, 'error': 'Token is missing'}), 401
        
        try:
            import jwt
            payload = jwt.decode(token, os.getenv('JWT_SECRET_KEY', 'dev-secret-key'), algorithms=['HS256'])
            request.user_id = payload.get('user_id')
            request.user_role = payload.get('role', 'user')
        except Exception as e:
            return jsonify({'success': False, 'error': 'Invalid token'}), 401
        
        return f(*args, **kwargs)
    return decorated

def create_app(config_name='default'):
    app = Flask(__name__)
    
    # Load configuration
    from config import config
    app.config.from_object(config[config_name])
    
    # ============================================================
    # SESSION CONFIGURATION
    # ============================================================
    app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', os.getenv('JWT_SECRET_KEY', 'dev-secret-key-change-in-production'))
    app.config['SESSION_TYPE'] = os.getenv('SESSION_TYPE', 'filesystem')
    app.config['SESSION_PERMANENT'] = False
    app.config['SESSION_USE_SIGNER'] = True
    app.config['SESSION_KEY_PREFIX'] = 'blog_oauth_'
    app.config['SESSION_FILE_DIR'] = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'flask_session')
    
    # Buat folder session jika belum ada
    os.makedirs(app.config['SESSION_FILE_DIR'], exist_ok=True)
    
    # Initialize session extension
    Session(app)
    
    # Setup logging untuk production
    if not app.debug and app.config.get('LOG_FILE'):
        try:
            log_file = app.config.get('LOG_FILE', 'blog_app.log')
            log_level = app.config.get('LOG_LEVEL', 'INFO')
            
            log_dir = os.path.dirname(log_file)
            if log_dir and not os.path.exists(log_dir):
                os.makedirs(log_dir, exist_ok=True)
            
            handler = logging.FileHandler(log_file)
            handler.setLevel(getattr(logging, log_level))
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            app.logger.addHandler(handler)
        except Exception as e:
            app.logger.warning(f"Could not setup file logging: {e}")
    
    # Initialize extensions
    from extensions import db, migrate
    
    # ============================================================
    # CORS CONFIGURATION - DIPERBAIKI
    # ============================================================
    
    # Daftar origin yang diizinkan
    allowed_origins = [
        'https://www.ruangbebas.web.id',
        'https://ruangbebas.web.id',
        'https://chronicle-two-kappa.vercel.app',
        'https://www.chronicle-two-kappa.vercel.app',
        'http://localhost:3000',
        'http://localhost:5000',
        'http://localhost:3001',
        'https://blog.pipinipon.site',
        'https://www.blog.pipinipon.site',
    ]
    
    # Konfigurasi CORS yang lebih sederhana dan efektif
    CORS(app, 
         origins=allowed_origins,
         supports_credentials=True,
         allow_headers=['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'Origin', 'Access-Control-Request-Method', 'Access-Control-Request-Headers'],
         methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
         expose_headers=['Content-Type', 'Authorization'],
         max_age=86400)
    
    db.init_app(app)
    migrate.init_app(app, db)
    
    # ============================================================
    # MIDDLEWARE CORS - TAMBAHAN UNTUK PASTIKAN
    # ============================================================
    @app.after_request
    def add_cors_headers(response):
        origin = request.headers.get('Origin')
        # Izinkan semua origin yang sudah terdaftar
        if origin and origin in allowed_origins:
            response.headers['Access-Control-Allow-Origin'] = origin
            response.headers['Access-Control-Allow-Credentials'] = 'true'
            response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS, PATCH'
            response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Accept, Origin'
            response.headers['Access-Control-Max-Age'] = '86400'
        return response
    
    # OPTIONS handler untuk semua route (CORS preflight)
    @app.route('/<path:path>', methods=['OPTIONS'])
    @app.route('/', methods=['OPTIONS'])
    def handle_options(path=None):
        response = jsonify({'success': True})
        origin = request.headers.get('Origin')
        if origin and origin in allowed_origins:
            response.headers['Access-Control-Allow-Origin'] = origin
            response.headers['Access-Control-Allow-Credentials'] = 'true'
            response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS, PATCH'
            response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Accept, Origin'
            response.headers['Access-Control-Max-Age'] = '86400'
        return response, 200
    
    # ============================================================
    # KONFIGURASI UPLOAD FILE
    # ============================================================
    PROFILE_UPLOAD_FOLDER = 'uploads/profile'
    SERIES_UPLOAD_FOLDER = 'uploads/series'
    ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
    MAX_FILE_SIZE = 5 * 1024 * 1024  # 5MB
    
    # Pastikan folder upload ada
    os.makedirs(PROFILE_UPLOAD_FOLDER, exist_ok=True)
    os.makedirs(SERIES_UPLOAD_FOLDER, exist_ok=True)
    
    def allowed_file(filename):
        return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
    
    # Serve uploaded files - profile
    @app.route('/uploads/profile/<path:filename>')
    def serve_profile_image(filename):
        return send_from_directory(PROFILE_UPLOAD_FOLDER, filename)
    
    # Serve uploaded files - series
    @app.route('/uploads/series/<path:filename>')
    def serve_series_image(filename):
        return send_from_directory(SERIES_UPLOAD_FOLDER, filename)
    
    # ============================================================
    # UPLOAD ENDPOINTS
    # ============================================================
    
    # Upload series cover
    @app.route('/api/series/upload-cover', methods=['POST', 'OPTIONS'])
    @token_required
    def upload_series_cover():
        """Upload cover image untuk series"""
        if request.method == 'OPTIONS':
            return jsonify({'success': True}), 200
            
        try:
            if 'image' not in request.files:
                return jsonify({'success': False, 'error': 'No image file provided'}), 400
            
            file = request.files['image']
            
            if file.filename == '':
                return jsonify({'success': False, 'error': 'No file selected'}), 400
            
            # Validasi file
            if not allowed_file(file.filename):
                return jsonify({'success': False, 'error': 'File type not allowed. Use PNG, JPG, JPEG, GIF, or WEBP'}), 400
            
            # Validasi ukuran (5MB)
            file.seek(0, 2)
            file_size = file.tell()
            file.seek(0)
            
            if file_size > MAX_FILE_SIZE:
                return jsonify({'success': False, 'error': f'File too large. Max 5MB. Your file: {file_size / (1024 * 1024):.2f}MB'}), 400
            
            # Buat filename unik
            ext = file.filename.rsplit('.', 1)[1].lower()
            filename = f"series_cover_{uuid.uuid4().hex[:8]}_{int(datetime.now().timestamp())}.{ext}"
            filename = secure_filename(filename)
            
            # Simpan file
            file_path = os.path.join(SERIES_UPLOAD_FOLDER, filename)
            file.save(file_path)
            
            # Return URL
            image_url = f"/uploads/series/{filename}"
            
            return jsonify({
                'success': True,
                'data': {
                    'url': image_url,
                    'filename': filename,
                    'size': file_size
                }
            }), 200
            
        except Exception as e:
            app.logger.error(f"Error uploading series cover: {str(e)}")
            return jsonify({'success': False, 'error': str(e)}), 500
    
    # ============================================================
    # HEALTH CHECK
    # ============================================================
    @app.route('/health', methods=['GET', 'HEAD', 'OPTIONS'])
    def health_check():
        if request.method == 'OPTIONS':
            return jsonify({'success': True}), 200
            
        db_status = 'connected'
        try:
            db.session.execute('SELECT 1')
        except Exception as e:
            db_status = f'disconnected: {str(e)}'
        
        if request.method == 'HEAD':
            return '', 200
        
        return jsonify({
            'success': True,
            'status': 'healthy',
            'timestamp': datetime.now().isoformat(),
            'service': app.config.get('API_TITLE', 'Blog API'),
            'version': app.config.get('API_VERSION', '1.0.0'),
            'environment': app.config.get('FLASK_ENV', 'development'),
            'database': db_status,
            'maintenance_mode': app.config.get('MAINTENANCE_MODE', False),
            'upload_folders': {
                'profile': PROFILE_UPLOAD_FOLDER,
                'series': SERIES_UPLOAD_FOLDER
            },
            'session_support': True,
            'google_oauth_configured': bool(app.config.get('GOOGLE_CLIENT_ID'))
        })
    
    # Maintenance mode middleware
    @app.before_request
    def check_maintenance():
        if app.config.get('MAINTENANCE_MODE', False):
            if request.path != '/health' and not request.path.startswith('/api/docs') and not request.path.startswith('/uploads'):
                return jsonify({
                    'success': False,
                    'error': 'maintenance',
                    'message': app.config.get('MAINTENANCE_MESSAGE', 'Server is under maintenance.')
                }), 503
    
    # Register blueprints
    from routes import api_bp
    api_prefix = app.config.get('API_PREFIX', '/api')
    app.register_blueprint(api_bp, url_prefix=api_prefix)
    
    # ============================================================
    # ERROR HANDLERS
    # ============================================================
    @app.errorhandler(404)
    def not_found(error):
        return jsonify({'success': False, 'error': 'Resource not found', 'code': 404}), 404
    
    @app.errorhandler(500)
    def internal_error(error):
        db.session.rollback()
        app.logger.error(f'Internal server error: {error}')
        return jsonify({'success': False, 'error': 'Internal server error', 'code': 500}), 500
    
    @app.errorhandler(400)
    def bad_request(error):
        return jsonify({'success': False, 'error': 'Bad request', 'code': 400}), 400
    
    @app.errorhandler(403)
    def forbidden(error):
        return jsonify({'success': False, 'error': 'Forbidden', 'code': 403}), 403
    
    @app.errorhandler(401)
    def unauthorized(error):
        return jsonify({'success': False, 'error': 'Unauthorized', 'code': 401}), 401
    
    # ============================================================
    # ROOT ENDPOINT
    # ============================================================
    @app.route('/', methods=['GET', 'OPTIONS'])
    def root():
        if request.method == 'OPTIONS':
            return jsonify({'success': True}), 200
            
        return jsonify({
            'success': True,
            'message': f'Welcome to {app.config.get("API_TITLE", "Blog API")}',
            'version': app.config.get('API_VERSION', '1.0.0'),
            'documentation': f'{app.config.get("API_PREFIX", "/api")}/docs',
            'health': '/health',
            'timestamp': datetime.now().isoformat()
        })
    
    return app

# Untuk cPanel Passenger WSGI
application = create_app(os.getenv('FLASK_ENV', 'production'))

if __name__ == '__main__':
    app = create_app(os.getenv('FLASK_ENV', 'development'))
    
    print("=" * 60)
    print(f"🚀 {app.config.get('API_TITLE', 'Blog API')} v{app.config.get('API_VERSION', '1.0.0')}")
    print("=" * 60)
    print(f"📡 Server: http://{app.config.get('HOST', '0.0.0.0')}:{app.config.get('PORT', 5000)}")
    print(f"📚 Swagger UI: http://{app.config.get('HOST', '0.0.0.0')}:{app.config.get('PORT', 5000)}{app.config.get('API_PREFIX', '/api')}/docs")
    print(f"❤️  Health Check: http://{app.config.get('HOST', '0.0.0.0')}:{app.config.get('PORT', 5000)}/health")
    print(f"🌍 Environment: {app.config.get('FLASK_ENV', 'development')}")
    
    debug_mode = app.config.get('DEBUG', True)
    print(f"🔧 Debug Mode: {debug_mode}")
    
    db_name = app.config.get('DB_NAME', 'unknown')
    db_host = app.config.get('DB_HOST', 'localhost')
    db_port = app.config.get('DB_PORT', 3306)
    print(f"💾 Database: {db_name} on {db_host}:{db_port}")
    print(f"🔗 CORS Origins: {allowed_origins}")
    print(f"📁 Upload Folders:")
    print(f"   - Profile: uploads/profile")
    print(f"   - Series: uploads/series")
    
    # Session info
    print(f"🔐 Session Type: {app.config.get('SESSION_TYPE', 'filesystem')}")
    print(f"🔑 Session Directory: {app.config.get('SESSION_FILE_DIR', 'flask_session')}")
    
    # Google OAuth status
    google_client_id = app.config.get('GOOGLE_CLIENT_ID')
    if google_client_id and google_client_id != 'your_google_client_id.apps.googleusercontent.com':
        print(f"✅ Google OAuth: Configured")
    else:
        print(f"⚠️  Google OAuth: Not Configured (set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET)")
    
    print("=" * 60)
    print("\n🔐 AUTHENTICATION:")
    print("   Swagger UI: Click 'Authorize' button → Enter 'Bearer YOUR_TOKEN'")
    print("\n📸 UPLOAD ENDPOINTS:")
    print("   POST /api/users/upload/profile-picture - Upload profile picture")
    print("   POST /api/users/upload/cover-photo - Upload cover photo")
    print("   POST /api/series/upload-cover - Upload series cover image")
    print("\n🔑 GOOGLE OAUTH:")
    print("   GET /api/auth/google - Start Google login")
    print("   GET /api/auth/google/callback - Google OAuth callback")
    print("=" * 60)
    
    app.run(
        host=app.config.get('HOST', '0.0.0.0'),
        port=app.config.get('PORT', 5000),
        debug=debug_mode
    )