# repository/server_repo.py
import asyncio
import datetime

from sqlalchemy import select
from ws_package.models.base import AppConfig, async_session
from ws_package.entities.s3bucket_entity import S3BucketEntity
from ws_package.log.writer import LogWriter
from ws_package.utils.db_lock_manager import db_lock_manager


logger = LogWriter.file(__name__)

DB_OPERATION_TIMEOUT = 5.0


class ServerManager:
    # Removed individual db_write_lock - now using centralized db_lock_manager
    
    async def save_s3bucket(self, s3bucketentity: S3BucketEntity, org_id: int):
        """
        Save S3 bucket details to database.
        
        NOTE: S3 configuration is critical and needed immediately after saving,
        so we use direct write instead of queue to avoid race conditions.
        
        Args:
            s3bucketentity: S3BucketEntity to save
            org_id: Organization ID to associate with
            
        Returns:
            s3bucketentity for backward compatibility
        """
        try:
            org_id = int(org_id)
            entity_data = s3bucketentity.model_dump()
            entity_data["org_id"] = org_id
            entity_data["timestamp"] = datetime.datetime.now()

            with db_lock_manager.write_lock():
                async with async_session() as session:
                    query = select(AppConfig).where(AppConfig.org_id == org_id)
                    result = await session.execute(query)
                    existing_config = result.scalar_one_or_none()

                    if existing_config:
                        for key, value in entity_data.items():
                            if hasattr(existing_config, key) and key != "id":
                                setattr(existing_config, key, value)
                        logger.info("Updated app_config for org_id=%s", org_id)
                    else:
                        session.add(AppConfig(**entity_data))
                        logger.info("Inserted app_config for org_id=%s", org_id)

                    await asyncio.wait_for(session.commit(), timeout=DB_OPERATION_TIMEOUT)

            return s3bucketentity

        except Exception as e:
            logger.error("Error saving app_config for org_id %s: %s", org_id, e, exc_info=True)
            return False
    
    async def get_s3bucket(self, org_id: int):
        """
        Get S3 bucket configuration for org_id
        
        Returns:
            AppConfig instance with decrypted fields, or None if not found
        """
        try:
            org_id = int(org_id)
            # Use centralized read lock for database read operations
            with db_lock_manager.read_lock():
                async with async_session() as session:
                    result = (await session.scalars(
                        select(AppConfig).where(AppConfig.org_id == org_id)
                    )).first()
                    
                    if not result:
                        logger.debug("No S3 configuration found for org_id: %s", org_id)
                        return None
                    
                    # CRITICAL: Access all attributes while session is still open
                    # Extract values before decrypting to ensure they're loaded
                    access_key = result.access_key
                    secret_access_key = result.secret_access_key
                    bucket = result.bucket
                    region = result.region
                    
                    # Decrypt fields after loading (if not already decrypted by event handler)
                    try:
                        from ws_package.models.base import _decrypt_app_config_fields
                        _decrypt_app_config_fields(result)
                    except Exception as decrypt_error:
                        logger.warning("Error decrypting AppConfig for org_id %s: %s", org_id, decrypt_error)
                        # Continue anyway - fields might already be decrypted or plaintext
                    
                    # Verify decryption worked by checking if fields are still encrypted
                    # If still encrypted, try manual decryption
                    if result.access_key and '$' in str(result.access_key):
                        logger.warning("Access key still encrypted after decryption attempt for org_id %s", org_id)
                    
                    return result
        except Exception as e:
            logger.error("Error retrieving S3 configuration for org_id %s: %s", org_id, e, exc_info=True)
            return None


server_manager = ServerManager()
