"""Lightweight background task execution for tenant-level operations with retry logic and status tracking."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_utils_bgtsk.ipynb.

# %% auto #0
__all__ = ['logger', 'TenantJob', 'BackgroundTaskManager']

# %% ../nbs/03_utils_bgtsk.ipynb #54fb88a4
from datetime import datetime
from typing import Optional, Callable, Any
import json
import traceback
import asyncio
import logging
from starlette.background import BackgroundTask
from fastcore.utils import *
from fastsql.core import *
from nbdev.showdoc import show_doc
from .db_host import timestamp, gen_id

# Module-level logger - configured by app via configure_logging()
logger = logging.getLogger(__name__)


# %% ../nbs/03_utils_bgtsk.ipynb #e005e003
class TenantJob:
    """Tenant-level background job with retry support."""
    id: str
    job_type: str
    status: str  # 'pending', 'running', 'completed', 'failed'
    payload: str  # JSON string
    result: str = None  # JSON string
    error_log: str = None
    retry_count: int = 0
    max_retries: int = 3
    created_at: str = None
    started_at: str = None
    completed_at: str = None

# %% ../nbs/03_utils_bgtsk.ipynb #f66a88cc
class BackgroundTaskManager:
    """Lightweight background task manager for tenant-level operations."""
    
    def __init__(self, db: Database):
        """Initialize with tenant database."""
        self.db = db
        self.tenant_jobs = db.create(TenantJob, name="tenant_jobs", pk='id')
    
    def submit(self, job_type: str, task_func: Callable, max_retries: int = 3, **task_kwargs) -> tuple[str, BackgroundTask]:
        """Submit a new background task for execution."""
        job_id = gen_id()
        job = TenantJob(
            id=job_id,
            job_type=job_type,
            status='pending',
            payload=json.dumps(task_kwargs),
            max_retries=max_retries,
            created_at=timestamp()
        )
        self.tenant_jobs.insert(job)
        
        bg_task = BackgroundTask(
            self._execute_with_retry,
            job_id=job_id,
            task_func=task_func,
            **task_kwargs
        )
        
        return job_id, bg_task
    
    def _execute_with_retry(self, job_id: str, task_func: Callable, **task_kwargs):
        """Execute task with automatic retry logic and status tracking."""
        job = self.tenant_jobs[job_id]
        
        try:
            self.tenant_jobs.update(id=job_id, status='running', started_at=timestamp())
            result = task_func(**task_kwargs)
            self.tenant_jobs.update(
                id=job_id,
                status='completed',
                result=json.dumps(result) if result else None,
                completed_at=timestamp()
            )
        except Exception as e:
            self._handle_failure(job_id, job, e)
    
    def _handle_failure(self, job_id: str, job: TenantJob, error: Exception):
        """Handle task failure with retry logic."""
        error_msg = f"{type(error).__name__}: {str(error)}\n{traceback.format_exc()}"
        retry_count = job.retry_count + 1
        
        logger.error(f"Job {job_id} ({job.job_type}) failed (attempt {retry_count}/{job.max_retries}): {error}", exc_info=True)
        
        if retry_count < job.max_retries:
            self.tenant_jobs.update(id=job_id, status='pending', retry_count=retry_count, error_log=error_msg)
        else:
            self.tenant_jobs.update(id=job_id, status='failed', retry_count=retry_count, error_log=error_msg, completed_at=timestamp())
    
    def get_job(self, job_id: str) -> TenantJob:
        """Get job status and details."""
        return self.tenant_jobs[job_id]
    
    def list_jobs(self, job_type: Optional[str] = None, status: Optional[str] = None, limit: int = 100) -> list[TenantJob]:
        """List jobs with optional filtering."""
        where_clauses = []
        if job_type:
            where_clauses.append(f"job_type = '{job_type}'")
        if status:
            where_clauses.append(f"status = '{status}'")
        
        where = " AND ".join(where_clauses) if where_clauses else None
        return self.tenant_jobs(where=where, order_by="created_at DESC", limit=limit)
