"""
SeaBot - Real Estate Posts Parser and Analyzer
Main entry point
"""

import os
import sys
import logging
import asyncio
import signal

# Fix encoding for Windows
if sys.platform == 'win32':
    os.environ['PYTHONIOENCODING'] = 'utf-8'
    if hasattr(sys.stdout, 'reconfigure'):
        sys.stdout.reconfigure(encoding='utf-8')
        sys.stderr.reconfigure(encoding='utf-8')

from dotenv import load_dotenv

from src.database.db import init_db, close_db
from src.bot.bot import SeaBot
from src.scheduler.updater import ParserScheduler
from src.constants import DEFAULT_PARSE_INTERVAL_HOURS, DEFAULT_DATABASE_URL

# Load environment variables
load_dotenv()

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('seabot.log'),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)


class SeaBotApplication:
    """Main application class"""

    def __init__(self):
        """Initialize application"""
        self.bot = None
        self.scheduler = None
        self._shutdown = False
        self._shutdown_event = asyncio.Event()

    async def startup(self):
        """Initialize and start all components"""
        logger.info("=" * 60)
        logger.info("SeaBot - Real Estate Posts Parser and Analyzer")
        logger.info("=" * 60)
        
        try:
            # Initialize database
            logger.info("Initializing database...")
            if not init_db():
                raise Exception("Failed to initialize database")
            
            # Create sessions directory for parsers
            os.makedirs('sessions', exist_ok=True)
            logger.info("Sessions directory ready")
            
            # Initialize scheduler
            logger.info("Initializing scheduler...")
            self.scheduler = ParserScheduler('config/sources.yaml')
            
            # Get interval from environment or use default from constants
            interval_hours = int(os.getenv('PARSE_INTERVAL_HOURS', str(DEFAULT_PARSE_INTERVAL_HOURS)))
            self.scheduler.start(interval_hours=interval_hours)
            
            # Run initial parsing immediately after scheduler starts
            logger.info("Running initial parsing...")
            try:
                # Create task for initial parsing
                asyncio.create_task(self.scheduler.parse_all_sources())
                logger.info("Initial parsing task created, will run in background")
            except Exception as e:
                logger.warning(f"Could not start initial parsing: {e}")
            
            # Initialize bot
            logger.info("Initializing Telegram bot...")
            self.bot = SeaBot(scheduler=self.scheduler)
            
            logger.info("=" * 60)
            logger.info("[OK] All components initialized successfully")
            logger.info("=" * 60)
            
        except Exception as e:
            logger.error(f"✗ Failed to start application: {e}")
            raise

    async def run(self):
        """Run the application"""
        try:
            await self.startup()
            
            logger.info("Starting bot...")
            
            # Setup bot
            await self.bot.setup()
            
            logger.info("[OK] Bot is running. Waiting for shutdown signal...")
            
            # Start polling in background task
            polling_task = asyncio.create_task(self.bot.start())
            
            # Keep running until shutdown signal
            try:
                await self._shutdown_event.wait()
            finally:
                # Cancel polling task
                polling_task.cancel()
                try:
                    await polling_task
                except asyncio.CancelledError:
                    pass
            
        except KeyboardInterrupt:
            logger.info("Received keyboard interrupt")
            self._shutdown_event.set()
        except Exception as e:
            logger.error(f"Error running application: {e}")
        finally:
            await self.shutdown()

    async def shutdown(self):
        """Shutdown all components gracefully"""
        if self._shutdown:
            return
        
        self._shutdown = True
        
        logger.info("=" * 60)
        logger.info("Shutting down SeaBot...")
        logger.info("=" * 60)
        
        try:
            # Stop scheduler
            if self.scheduler:
                logger.info("Stopping scheduler...")
                self.scheduler.stop()
            
            # Stop bot
            if self.bot:
                logger.info("Stopping bot...")
                await self.bot.stop()
            
            # Close database
            logger.info("Closing database connections...")
            close_db()
            
            logger.info("=" * 60)
            logger.info("[OK] Shutdown complete")
            logger.info("=" * 60)
            
        except Exception as e:
            logger.error(f"Error during shutdown: {e}")


def signal_handler(signum, frame):
    """Handle shutdown signals"""
    logger.info(f"Received signal {signum}")
    # Signal will be handled by asyncio event loop


def main():
    """Main entry point"""
    # Create and run application
    app = SeaBotApplication()
    
    def signal_handler_local(signum, frame):
        """Handle shutdown signals"""
        logger.info(f"Received signal {signum}")
        app._shutdown = True
        app._shutdown_event.set()
    
    # Register signal handlers
    signal.signal(signal.SIGINT, signal_handler_local)
    signal.signal(signal.SIGTERM, signal_handler_local)
    
    try:
        asyncio.run(app.run())
    except KeyboardInterrupt:
        logger.info("Application stopped by user")
    except Exception as e:
        logger.error(f"Fatal error: {e}")
        sys.exit(1)


if __name__ == '__main__':
    main()

