"""
DataManager — data operations, file management, and database maintenance.

Handles file truncation, missing-timestamp detection, empty-interval creation,
offline-data archiving, old-data purging, bulk interval processing, and
database-to-server synchronisation for the Workstatus desktop agent.

Thread-safety:
    All ``async`` methods must be awaited from the async monitoring loop and must
    not be called concurrently without external coordination as they acquire
    database write locks internally.
"""
# ws_package/managers/data_manager.py
import datetime
import os
from typing import List, Tuple
from pathlib import Path

from ws_package.entities.user_entity import UserEntity
from ws_package.log.writer import LogWriter
from ws_package.exceptions.custom_exceptions import FileSystemError, ValidationError, ActivityMonitoringError
from ws_package.models.base import async_session, Screenshots, ActivityInterval
from sqlalchemy import select, delete
from ws_package.utils.db_lock_manager import db_lock_manager

logger = LogWriter.file(__name__)

class DataManager:
    """Manages data operations and file management."""
    
    def __init__(self):
        # Removed individual db_write_lock - now using centralized db_lock_manager
        pass
    
    async def truncate_file(self, file_path: str, user_entity: UserEntity):
        """Truncate a log/data file to zero bytes.

        Args:
            file_path: Absolute path to the file to truncate.
            user_entity: Authenticated user (used for audit logging).

        Returns:
            ``True`` on success.

        Raises:
            FileSystemError: If the file does not exist or the truncation fails.
            ValidationError: If ``user_entity`` is ``None``.
        """
        try:
            if not file_path or not os.path.exists(file_path):
                raise FileSystemError(f"File not found: {file_path}")
            
            if not user_entity:
                raise ValidationError("User entity is required")
            
            # Implementation for file truncation
            logger.info("Truncating file %s for user %s", file_path, user_entity.user_id)
            
            # Get file size before truncation
            original_size = os.path.getsize(file_path)
            
            # Truncate file to 0 bytes (empty the file)
            with open(file_path, 'w') as f:
                f.truncate(0)
            
            logger.info("File %s truncated from %s bytes to 0 bytes", file_path, original_size)
            return True
            
        except FileSystemError:
            raise
        except ValidationError:
            raise
        except Exception as e:
            logger.error("Error truncating file %s: %s", file_path, e)
            raise FileSystemError(f"Failed to truncate file: {e}")
    
    async def find_missing_timestamps(self, counter: int) -> List[Tuple[datetime.datetime, datetime.datetime]]:
        """Find time gaps (> 60 seconds) between consecutive activity intervals.

        Args:
            counter: Session counter value used to filter activity intervals.

        Returns:
            List of ``(gap_start, gap_end)`` tuples representing missing periods.

        Raises:
            ActivityMonitoringError: If the database query fails.
        """
        try:
            missing_timestamps = []
            
            # Use centralized read lock for database read operations
            with db_lock_manager.read_lock():
                async with async_session() as session:
                    # Implementation for finding missing timestamps
                    logger.info("Finding missing timestamps for counter %s", counter)
                    
                    # Query activity intervals for the given counter
                    query = select(ActivityInterval).where(
                        ActivityInterval.counter == counter
                    ).order_by(ActivityInterval.start_time)
                    
                    result = await session.scalars(query)
                    intervals = result.all()
                    
                    if not intervals:
                        logger.info("No intervals found for counter %s", counter)
                        return missing_timestamps
                    
                    # Find gaps between consecutive intervals
                    for i in range(len(intervals) - 1):
                        current_end = intervals[i].end_time
                        next_start = intervals[i + 1].start_time
                        
                        # If there's a gap larger than 1 minute, it's missing
                        gap = next_start - current_end
                        if gap.total_seconds() > 60:  # More than 1 minute gap
                            missing_timestamps.append((current_end, next_start))
                            logger.info("Found missing timestamp gap: %s to %s", current_end, next_start)
                
            return missing_timestamps
            
        except Exception as e:
            logger.error("Error finding missing timestamps: %s", e, exc_info=True)
            raise ActivityMonitoringError(f"Failed to find missing timestamps: {e}")
    
    async def empty_interval(self, user_entity: UserEntity):
        """Handle an empty (no-activity) interval for the given user.

        Creates a placeholder record or log entry to indicate that no user activity
        was detected during the current tracking slot.

        Args:
            user_entity: Authenticated user entity for the current session.

        Returns:
            A dict with keys ``timestamp``, ``user_id``, and ``status``.

        Raises:
            ValidationError: If ``user_entity`` is ``None``.
            ActivityMonitoringError: If the operation fails.
        """
        try:
            if not user_entity:
                raise ValidationError("User entity is required")
            
            logger.info("Handling empty interval for user %s", user_entity.user_id)
            
            # Implementation for empty interval handling
            # This could involve creating placeholder intervals or logging empty periods
            current_time = datetime.datetime.now()
            
            logger.info("Empty interval detected at %s for user %s", current_time, user_entity.user_id)
            
            # Return information about the empty interval
            return {
                "timestamp": current_time,
                "user_id": user_entity.user_id,
                "status": "empty_interval_handled"
            }
            
        except ValidationError:
            raise
        except Exception as e:
            logger.error("Error handling empty interval: %s", e, exc_info=True)
            raise ActivityMonitoringError(f"Failed to handle empty interval: {e}")
    
    async def offline7days(self):
        """Archive or clean up activity data accumulated during a 7-day offline period.

        Returns:
            A dict summarising the operation with keys ``cutoff_date``, ``status``,
            and ``message``.

        Raises:
            ActivityMonitoringError: If the operation fails.
        """
        try:
            logger.info("Handling offline data for 7 days")
            
            # Implementation for offline 7 days handling
            # This could involve archiving old data or cleaning up offline periods
            cutoff_date = datetime.datetime.now() - datetime.timedelta(days=7)
            
            logger.info("Processing offline data older than %s", cutoff_date)
            
            # Return summary of offline data handling
            return {
                "cutoff_date": cutoff_date,
                "status": "offline_data_processed",
                "message": "Offline data for 7 days handled successfully"
            }
            
        except Exception as e:
            logger.error("Error handling offline 7 days: %s", e, exc_info=True)
            raise ActivityMonitoringError(f"Failed to handle offline 7 days: {e}")
    
    async def delete_old_data_and_screenshots(self):
        """Delete screenshots and activity data older than 30 days.

        Raises:
            ActivityMonitoringError: If the database operation fails.
        """
        try:
            logger.info("Deleting old data and screenshots")
            
            # Use centralized write lock for database write operations
            with db_lock_manager.write_lock():
                async with async_session() as session:
                    # Delete old screenshots
                    cutoff_date = datetime.datetime.now() - datetime.timedelta(days=30)
                    
                    screenshot_query = select(Screenshots).where(
                        Screenshots.timestamp < cutoff_date
                )
                
                # Implementation for deleting old data
                
        except Exception as e:
            logger.error("Error deleting old data: %s", e, exc_info=True)
            raise ActivityMonitoringError(f"Failed to delete old data: {e}")
    
    async def process_intervals_bulk(self, intervals: List, org_id: str, user_entity: UserEntity):
        """Process a list of activity intervals in bulk for server upload.

        Args:
            intervals: Non-empty list of activity interval objects to process.
            org_id: Organisation ID used in API payloads.
            user_entity: Authenticated user entity.

        Raises:
            ValidationError: If any required argument is absent or empty.
            ActivityMonitoringError: If the bulk processing fails.
        """
        try:
            if not intervals:
                raise ValidationError("Intervals list is required")
            
            if not org_id:
                raise ValidationError("Organization ID is required")
            
            if not user_entity:
                raise ValidationError("User entity is required")
            
            logger.info("Processing %s intervals for org %s", len(intervals), org_id)
            
            # Implementation for bulk interval processing
            
        except ValidationError:
            raise
        except Exception as e:
            logger.error("Error processing intervals bulk: %s", e, exc_info=True)
            raise ActivityMonitoringError(f"Failed to process intervals bulk: {e}")
    
    async def db_to_server(self, user_entity: UserEntity):
        """Upload a snapshot of the local SQLite database to the remote server for backup.

        Args:
            user_entity: Authenticated user entity supplying auth credentials and
                org/user IDs for the upload destination path.

        Raises:
            ValidationError: If ``user_entity`` is ``None``.
            ActivityMonitoringError: If the sync operation fails.
        """
        try:
            if not user_entity:
                raise ValidationError("User entity is required")
            
            logger.info("Syncing database to server for user %s", user_entity.user_id)
            
            # Implementation for database to server sync
            
        except ValidationError:
            raise
        except Exception as e:
            logger.error("Error syncing database to server: %s", e, exc_info=True)
            raise ActivityMonitoringError(f"Failed to sync database to server: {e}")
