# repository/screenshot_repo.py

import asyncio
from datetime import datetime
from typing import Optional
from sqlalchemy import select
from ws_package.models.base import Screenshots, async_session
from ws_package.entities.screenshot_entity import ScreenshotEntity
from ws_package.log.writer import LogWriter
from ws_package.utils.db_lock_manager import db_lock_manager
from ws_package.utils.db_write_queue import db_write_queue, WriteOperationType


logger = LogWriter.file(__name__)

# Database operation timeout (5 seconds)
DB_OPERATION_TIMEOUT = 5.0


class ScreenshotManager:
    # Removed individual db_write_lock - now using centralized db_lock_manager
    async def get_screenshots(self, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None):
        """Fetch screenshots within an optional time range.

        Args:
            start_date: Inclusive lower bound for screenshot timestamp.
            end_date: Inclusive upper bound for screenshot timestamp.

        Returns:
            Sequence of Screenshots ORM objects; empty list on error or timeout.
        """
        # Use centralized read lock for database read operations
        try:
            with db_lock_manager.read_lock():
                async with async_session() as session:
                    query = select(Screenshots)
                    if start_date is not None:
                        query = query.where(
                            Screenshots.timestamp >= start_date
                        )
                    if end_date is not None:
                        query = query.where(
                            Screenshots.timestamp <= end_date
                        )
                    result = await asyncio.wait_for(
                        session.scalars(query),
                        timeout=DB_OPERATION_TIMEOUT
                    )
                    return result.all()
        except asyncio.TimeoutError:
            logger.error("Database read operation timed out after %ss while getting screenshots", DB_OPERATION_TIMEOUT)
            return []
        except Exception as e:
            logger.error("Failed to get screenshots (start=%s, end=%s): %s", start_date, end_date, e, exc_info=True)
            return []

    async def save_screenshot(self, screenshot_entity: ScreenshotEntity):
        """
        Save screenshot to in-memory queue.
        The database writer thread will process this asynchronously.
        
        Returns:
            screenshot_entity for backward compatibility
        """
        try:
            # Enqueue to in-memory queue (non-blocking, no SQLite operation)
            success = db_write_queue.enqueue(
                operation_type=WriteOperationType.SCREENSHOT,
                table_name="screenshots",
                data=screenshot_entity.model_dump()
            )
            
            if success:
                logger.debug("Enqueued Screenshot: %s", screenshot_entity.file_name)
                # Return entity for backward compatibility
                return screenshot_entity
            else:
                logger.error("Failed to enqueue Screenshot - queue may be full")
                return False
                
        except Exception as e:
            logger.error("Error enqueueing Screenshot: %s", e, exc_info=True)
            return False
    
    async def update_screenshot(self, screenshot: Screenshots):
        """
        Update screenshot via in-memory queue.
        The database writer thread will process this asynchronously.
        
        Args:
            screenshot: Screenshots ORM object with id attribute
            
        Returns:
            screenshot object for backward compatibility
        """
        try:
            # Extract record ID
            record_id = screenshot.id if hasattr(screenshot, 'id') else None
            if not record_id:
                logger.error("update_screenshot requires screenshot with id")
                return False
            
            # Prepare update data
            update_data = {'is_uploaded': True}
            
            # Enqueue update operation (non-blocking, no SQLite)
            success = db_write_queue.enqueue(
                operation_type=WriteOperationType.UPDATE_SCREENSHOT,
                table_name="screenshots",
                data=update_data,
                record_id=record_id
            )
            
            if success:
                logger.debug("Enqueued Screenshot update for id: %s", record_id)
                # Return original object for backward compatibility
                return screenshot
            else:
                logger.error("Failed to enqueue Screenshot update - queue may be full")
                return False
                
        except Exception as e:
            logger.error("Error enqueueing Screenshot update: %s", e, exc_info=True)
            return False

    async def get_pending_uploads(self, max_age_hours: int = 24) -> list:
        """Return screenshots not yet uploaded to S3 (is_uploaded=False), up to 24 h old.

        These are retried by ScreenshotService.retry_pending_uploads() when connectivity
        is restored after an offline period.
        """
        from datetime import datetime, timedelta
        cutoff = datetime.utcnow() - timedelta(hours=max_age_hours)
        try:
            with db_lock_manager.read_lock():
                async with async_session() as session:
                    query = (
                        select(Screenshots)
                        .where(Screenshots.is_uploaded.is_(False))
                        .where(Screenshots.timestamp >= cutoff)
                        .order_by(Screenshots.timestamp)
                        .limit(20)
                    )
                    result = await asyncio.wait_for(
                        session.scalars(query),
                        timeout=DB_OPERATION_TIMEOUT,
                    )
                    return list(result.all())
        except asyncio.TimeoutError:
            logger.error("Timeout fetching pending screenshot uploads")
            return []
        except Exception as e:
            logger.error("Failed to get pending screenshot uploads: %s", e, exc_info=True)
            return []

    async def mark_uploaded(self, screenshot_id: int) -> bool:
        """Mark a screenshot row as successfully uploaded (sets both is_uploaded and is_s3_uploaded)."""
        try:
            success = db_write_queue.enqueue(
                operation_type=WriteOperationType.UPDATE_SCREENSHOT,
                table_name="screenshots",
                data={'is_uploaded': True, 'is_s3_uploaded': True},
                record_id=screenshot_id,
            )
            if success:
                logger.debug("Marked screenshot %s as uploaded", screenshot_id)
            return bool(success)
        except Exception as e:
            logger.error("Failed to mark screenshot %s as uploaded: %s", screenshot_id, e, exc_info=True)
            return False


screenshot_manager = ScreenshotManager()
