"""
Background Job: Sync POS Transactions to Sales Service

This job runs periodically to sync unsynced POS transactions to the sales service,
which automatically decreases inventory stock levels.

Schedule: Every 5 minutes (configurable)
"""

import asyncio
from datetime import datetime, timedelta
from typing import Dict, Any
import structlog

from app.services.pos_transaction_service import POSTransactionService
from app.repositories.pos_config_repository import POSConfigRepository
from app.core.database import get_db_transaction

logger = structlog.get_logger()


class POSToSalesSyncJob:
    """Background job for syncing POS transactions to sales service"""

    def __init__(self):
        self.transaction_service = POSTransactionService()
        self.batch_size = 50  # Process 50 transactions per batch
        self.max_retries = 3  # Max retry attempts for failed syncs

    async def run(self):
        """
        Main job execution method

        This method:
        1. Finds all tenants with active POS configurations
        2. For each tenant, syncs unsynced transactions
        3. Logs results and errors
        """
        start_time = datetime.utcnow()
        logger.info("Starting POS to Sales sync job")

        try:
            # Get all tenants with active POS configurations
            tenants_to_sync = await self._get_active_tenants()

            if not tenants_to_sync:
                logger.info("No active tenants found for sync")
                return {
                    "success": True,
                    "tenants_processed": 0,
                    "total_synced": 0,
                    "total_failed": 0
                }

            total_synced = 0
            total_failed = 0
            results = []

            for tenant_id in tenants_to_sync:
                try:
                    result = await self.transaction_service.sync_unsynced_transactions(
                        tenant_id=tenant_id,
                        limit=self.batch_size
                    )

                    synced = result.get("synced", 0)
                    failed = result.get("failed", 0)

                    total_synced += synced
                    total_failed += failed

                    results.append({
                        "tenant_id": str(tenant_id),
                        "synced": synced,
                        "failed": failed
                    })

                    logger.info("Tenant sync completed",
                              tenant_id=str(tenant_id),
                              synced=synced,
                              failed=failed)

                except Exception as e:
                    logger.error("Failed to sync tenant",
                               tenant_id=str(tenant_id),
                               error=str(e))
                    results.append({
                        "tenant_id": str(tenant_id),
                        "error": str(e)
                    })

            duration = (datetime.utcnow() - start_time).total_seconds()

            logger.info("POS to Sales sync job completed",
                       duration_seconds=duration,
                       tenants_processed=len(tenants_to_sync),
                       total_synced=total_synced,
                       total_failed=total_failed)

            return {
                "success": True,
                "tenants_processed": len(tenants_to_sync),
                "total_synced": total_synced,
                "total_failed": total_failed,
                "duration_seconds": duration,
                "results": results
            }

        except Exception as e:
            duration = (datetime.utcnow() - start_time).total_seconds()
            logger.error("POS to Sales sync job failed",
                       error=str(e),
                       duration_seconds=duration,
                       exc_info=True)

            return {
                "success": False,
                "error": str(e),
                "duration_seconds": duration
            }

    async def _get_active_tenants(self):
        """Get list of tenant IDs with active POS configurations"""
        try:
            async with get_db_transaction() as db:
                repository = POSConfigRepository(db)

                # Get all active POS configurations
                configs = await repository.get_all_active_configs()

                # Extract unique tenant IDs
                tenant_ids = list(set(config.tenant_id for config in configs))

                logger.info("Found tenants with active POS configs",
                          count=len(tenant_ids))

                return tenant_ids

        except Exception as e:
            logger.error("Failed to get active tenants", error=str(e))
            return []

    async def sync_specific_tenant(self, tenant_id: str) -> Dict[str, Any]:
        """
        Sync transactions for a specific tenant (for manual triggering)

        Args:
            tenant_id: Tenant UUID as string

        Returns:
            Sync result dictionary
        """
        try:
            from uuid import UUID
            tenant_uuid = UUID(tenant_id)

            result = await self.transaction_service.sync_unsynced_transactions(
                tenant_id=tenant_uuid,
                limit=self.batch_size
            )

            logger.info("Manual tenant sync completed",
                       tenant_id=tenant_id,
                       synced=result.get("synced"),
                       failed=result.get("failed"))

            return result

        except Exception as e:
            logger.error("Failed to sync specific tenant",
                       tenant_id=tenant_id,
                       error=str(e))
            return {
                "success": False,
                "error": str(e)
            }


# Singleton instance for use in schedulers
pos_to_sales_sync_job = POSToSalesSyncJob()


async def run_pos_to_sales_sync():
    """
    Entry point for scheduler

    Usage with APScheduler:
    ```python
    from apscheduler.schedulers.asyncio import AsyncIOScheduler
    from app.jobs.sync_pos_to_sales import run_pos_to_sales_sync

    scheduler = AsyncIOScheduler()
    scheduler.add_job(
        run_pos_to_sales_sync,
        'interval',
        minutes=5,
        id='pos_to_sales_sync'
    )
    scheduler.start()
    ```

    Usage with Celery:
    ```python
    from celery import Celery
    from app.jobs.sync_pos_to_sales import run_pos_to_sales_sync

    @celery.task
    def sync_pos_transactions():
        asyncio.run(run_pos_to_sales_sync())
    ```
    """
    return await pos_to_sales_sync_job.run()


if __name__ == "__main__":
    # For testing: Run sync manually
    asyncio.run(run_pos_to_sales_sync())
