from fastapi import FastAPI, Request, HTTPException, Depends, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import IntegrityError, OperationalError
from jose.exceptions import JWTError
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from pathlib import Path
from datetime import datetime
import sys
import secrets
import os
import re
from .config.settings import settings
from .config.logging_config import setup_logging, get_logger
from .config.database import engine, Base, get_db
from . import models
from sqlalchemy.orm import Session
logger = setup_logging()
logger.info(f'Starting {settings.APP_NAME} v{settings.APP_VERSION} in {settings.ENVIRONMENT} mode')
from .middleware.error_handler import validation_exception_handler, integrity_error_handler, jwt_error_handler, http_exception_handler, general_exception_handler
from .middleware.request_id import RequestIDMiddleware
from .middleware.security import SecurityHeadersMiddleware
from .middleware.timeout import TimeoutMiddleware
from .middleware.cookie_consent import CookieConsentMiddleware
if settings.is_development:
    logger.info('Creating database tables (development mode)')
    Base.metadata.create_all(bind=engine)
else:
    try:
        from .models.cookie_policy import CookiePolicy
        from .models.cookie_integration_config import CookieIntegrationConfig
        from .models.page_content import PageContent
        logger.info('Ensuring required tables exist')
        CookiePolicy.__table__.create(bind=engine, checkfirst=True)
        CookieIntegrationConfig.__table__.create(bind=engine, checkfirst=True)
        PageContent.__table__.create(bind=engine, checkfirst=True)
    except Exception as e:
        logger.error(f'Failed to ensure required tables exist: {e}')
from .routes import auth_routes
from .routes import privacy_routes
app = FastAPI(title=settings.APP_NAME, description='Enterprise-grade Hotel Booking API', version=settings.APP_VERSION, docs_url='/api/docs' if not settings.is_production else None, redoc_url='/api/redoc' if not settings.is_production else None, openapi_url='/api/openapi.json' if not settings.is_production else None)
app.add_middleware(RequestIDMiddleware)
app.add_middleware(CookieConsentMiddleware)
if settings.REQUEST_TIMEOUT > 0:
    app.add_middleware(TimeoutMiddleware)
app.add_middleware(SecurityHeadersMiddleware)
if settings.RATE_LIMIT_ENABLED:
    limiter = Limiter(key_func=get_remote_address, default_limits=[f'{settings.RATE_LIMIT_PER_MINUTE}/minute'])
    app.state.limiter = limiter
    app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
    logger.info(f'Rate limiting enabled: {settings.RATE_LIMIT_PER_MINUTE} requests/minute')
if settings.is_development:
    app.add_middleware(CORSMiddleware, allow_origin_regex='http://(localhost|127\\.0\\.0\\.1)(:\\d+)?', allow_credentials=True, allow_methods=['*'], allow_headers=['*'])
    logger.info('CORS configured for development (allowing localhost)')
else:
    app.add_middleware(CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], allow_headers=['*'])
    logger.info(f'CORS configured for production with {len(settings.CORS_ORIGINS)} allowed origins')
uploads_dir = Path(__file__).parent.parent / settings.UPLOAD_DIR
uploads_dir.mkdir(exist_ok=True)
app.mount('/uploads', StaticFiles(directory=str(uploads_dir)), name='uploads')
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(RequestValidationError, validation_exception_handler)
app.add_exception_handler(IntegrityError, integrity_error_handler)
app.add_exception_handler(JWTError, jwt_error_handler)
app.add_exception_handler(Exception, general_exception_handler)

@app.get('/health', tags=['health'])
@app.get('/api/health', tags=['health'])
async def health_check(db: Session=Depends(get_db)):
    health_status = {'status': 'healthy', 'timestamp': datetime.utcnow().isoformat(), 'service': settings.APP_NAME, 'version': settings.APP_VERSION, 'environment': settings.ENVIRONMENT, 'checks': {'api': 'ok', 'database': 'unknown'}}
    try:
        from sqlalchemy import text
        db.execute(text('SELECT 1'))
        health_status['checks']['database'] = 'ok'
    except OperationalError as e:
        health_status['status'] = 'unhealthy'
        health_status['checks']['database'] = 'error'
        health_status['error'] = str(e)
        logger.error(f'Database health check failed: {str(e)}')
        return JSONResponse(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, content=health_status)
    except Exception as e:
        health_status['status'] = 'unhealthy'
        health_status['checks']['database'] = 'error'
        health_status['error'] = str(e)
        logger.error(f'Health check failed: {str(e)}')
        return JSONResponse(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, content=health_status)
    return health_status

@app.get('/metrics', tags=['monitoring'])
async def metrics():
    return {'status': 'success', 'service': settings.APP_NAME, 'version': settings.APP_VERSION, 'environment': settings.ENVIRONMENT, 'timestamp': datetime.utcnow().isoformat()}
app.include_router(auth_routes.router, prefix='/api')
app.include_router(auth_routes.router, prefix=settings.API_V1_PREFIX)
from .routes import room_routes, booking_routes, payment_routes, invoice_routes, banner_routes, favorite_routes, service_routes, service_booking_routes, promotion_routes, report_routes, review_routes, user_routes, audit_routes, admin_privacy_routes, system_settings_routes, contact_routes, page_content_routes, home_routes, about_routes, contact_content_routes, footer_routes, chat_routes, privacy_routes, terms_routes, refunds_routes, cancellation_routes, accessibility_routes, faq_routes
app.include_router(room_routes.router, prefix='/api')
app.include_router(booking_routes.router, prefix='/api')
app.include_router(payment_routes.router, prefix='/api')
app.include_router(invoice_routes.router, prefix='/api')
app.include_router(banner_routes.router, prefix='/api')
app.include_router(favorite_routes.router, prefix='/api')
app.include_router(service_routes.router, prefix='/api')
app.include_router(service_booking_routes.router, prefix='/api')
app.include_router(promotion_routes.router, prefix='/api')
app.include_router(report_routes.router, prefix='/api')
app.include_router(review_routes.router, prefix='/api')
app.include_router(user_routes.router, prefix='/api')
app.include_router(audit_routes.router, prefix='/api')
app.include_router(admin_privacy_routes.router, prefix='/api')
app.include_router(system_settings_routes.router, prefix='/api')
app.include_router(contact_routes.router, prefix='/api')
app.include_router(home_routes.router, prefix='/api')
app.include_router(about_routes.router, prefix='/api')
app.include_router(contact_content_routes.router, prefix='/api')
app.include_router(footer_routes.router, prefix='/api')
app.include_router(privacy_routes.router, prefix='/api')
app.include_router(terms_routes.router, prefix='/api')
app.include_router(refunds_routes.router, prefix='/api')
app.include_router(cancellation_routes.router, prefix='/api')
app.include_router(accessibility_routes.router, prefix='/api')
app.include_router(faq_routes.router, prefix='/api')
app.include_router(chat_routes.router, prefix='/api')
app.include_router(room_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(booking_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(payment_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(invoice_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(banner_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(favorite_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(service_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(service_booking_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(promotion_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(report_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(review_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(user_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(audit_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(admin_privacy_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(system_settings_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(contact_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(home_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(about_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(contact_content_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(footer_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(privacy_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(terms_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(refunds_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(cancellation_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(accessibility_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(faq_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(chat_routes.router, prefix=settings.API_V1_PREFIX)
app.include_router(page_content_routes.router, prefix='/api')
app.include_router(page_content_routes.router, prefix=settings.API_V1_PREFIX)
logger.info('All routes registered successfully')

def ensure_jwt_secret():
    """Generate and save JWT secret if it's using the default value."""
    default_secret = 'dev-secret-key-change-in-production-12345'
    current_secret = settings.JWT_SECRET
    
    if not current_secret or current_secret == default_secret:
        new_secret = secrets.token_urlsafe(64)
        
        os.environ['JWT_SECRET'] = new_secret
        
        env_file = Path(__file__).parent.parent / '.env'
        if env_file.exists():
            try:
                env_content = env_file.read_text(encoding='utf-8')
                
                jwt_pattern = re.compile(r'^JWT_SECRET=.*$', re.MULTILINE)
                
                if jwt_pattern.search(env_content):
                    env_content = jwt_pattern.sub(f'JWT_SECRET={new_secret}', env_content)
                else:
                    jwt_section_pattern = re.compile(r'(# =+.*JWT.*=+.*\n)', re.IGNORECASE | re.MULTILINE)
                    match = jwt_section_pattern.search(env_content)
                    if match:
                        insert_pos = match.end()
                        env_content = env_content[:insert_pos] + f'JWT_SECRET={new_secret}\n' + env_content[insert_pos:]
                    else:
                        env_content += f'\nJWT_SECRET={new_secret}\n'
                
                env_file.write_text(env_content, encoding='utf-8')
                logger.info('✓ JWT secret generated and saved to .env file')
            except Exception as e:
                logger.warning(f'Could not update .env file: {e}')
                logger.info(f'Generated JWT secret (add to .env manually): JWT_SECRET={new_secret}')
        else:
            logger.info(f'Generated JWT secret (add to .env file): JWT_SECRET={new_secret}')
        
        logger.info('✓ Secure JWT secret generated automatically')
    else:
        logger.info('✓ JWT secret is configured')

@app.on_event('startup')
async def startup_event():
    ensure_jwt_secret()
    
    logger.info(f'{settings.APP_NAME} started successfully')
    logger.info(f'Environment: {settings.ENVIRONMENT}')
    logger.info(f'Debug mode: {settings.DEBUG}')
    logger.info(f'API version: {settings.API_V1_PREFIX}')

@app.on_event('shutdown')
async def shutdown_event():
    logger.info(f'{settings.APP_NAME} shutting down gracefully')
if __name__ == '__main__':
    import uvicorn
    from pathlib import Path
    base_dir = Path(__file__).parent.parent
    src_dir = str(base_dir / 'src')
    uvicorn.run('src.main:app', host=settings.HOST, port=settings.PORT, reload=settings.is_development, log_level=settings.LOG_LEVEL.lower(), reload_dirs=[src_dir] if settings.is_development else None, reload_excludes=['*.log', '*.pyc', '*.pyo', '*.pyd', '__pycache__', '**/__pycache__/**', '*.db', '*.sqlite', '*.sqlite3'], reload_delay=0.5)