"""Background report generation tasks."""

import asyncio
from datetime import datetime
from pathlib import Path
from uuid import UUID

from celery import shared_task
from celery.exceptions import SoftTimeLimitExceeded

from src.core.celery_app import celery_app
from src.core.database import AsyncSessionLocal
from src.core.logging_config import get_logger, set_correlation_id
from src.core.monitoring import metrics
from src.repositories.report import report_repository
from src.services.report_service import report_service


logger = get_logger(__name__)


@celery_app.task(
    bind=True,
    max_retries=3,
    default_retry_delay=60,
    time_limit=300,  # 5 minutes
    soft_time_limit=240,  # 4 minutes
)
def generate_pdf_report(
    self,
    scenario_id: str,
    report_id: str,
    include_sections: list[str] = None,
    date_from: str = None,
    date_to: str = None,
):
    """Generate PDF report asynchronously.

    Args:
        scenario_id: Scenario UUID string
        report_id: Report UUID string
        include_sections: List of sections to include
        date_from: Optional start date (ISO format)
        date_to: Optional end date (ISO format)
    """
    correlation_id = set_correlation_id()
    start_time = datetime.utcnow()

    logger.info(
        "Starting PDF report generation",
        extra={
            "scenario_id": scenario_id,
            "report_id": report_id,
            "correlation_id": correlation_id,
        },
    )

    try:
        # Run async code in sync context
        asyncio.run(
            _generate_pdf_async(
                scenario_id=UUID(scenario_id),
                report_id=UUID(report_id),
                include_sections=include_sections,
                date_from=datetime.fromisoformat(date_from) if date_from else None,
                date_to=datetime.fromisoformat(date_to) if date_to else None,
            )
        )

        # Track metrics
        duration = (datetime.utcnow() - start_time).total_seconds()
        metrics.observe_histogram(
            "reports_generation_duration_seconds",
            duration,
            labels={"format": "pdf"},
        )
        metrics.increment_counter(
            "reports_generated_total",
            labels={"format": "pdf"},
        )

        logger.info(
            "PDF report generation completed",
            extra={
                "report_id": report_id,
                "duration_seconds": duration,
            },
        )

        return {
            "status": "completed",
            "report_id": report_id,
            "duration_seconds": duration,
        }

    except SoftTimeLimitExceeded:
        logger.error(f"PDF generation timed out for report {report_id}")
        raise self.retry(exc=Exception("Generation timed out"), countdown=120)

    except Exception as exc:
        logger.exception(f"PDF generation failed for report {report_id}")
        raise self.retry(exc=exc, countdown=60)


async def _generate_pdf_async(
    scenario_id: UUID,
    report_id: UUID,
    include_sections: list[str] = None,
    date_from: datetime = None,
    date_to: datetime = None,
):
    """Async helper for PDF generation."""
    async with AsyncSessionLocal() as db:
        try:
            # Update report status to processing
            await report_repository.update_status(db, report_id, "processing")

            # Generate PDF
            file_path = await report_service.generate_pdf(
                db=db,
                scenario_id=scenario_id,
                report_id=report_id,
                include_sections=include_sections,
                date_from=date_from,
                date_to=date_to,
            )

            # Update report with file size
            file_size = file_path.stat().st_size
            await report_repository.update_file_size(db, report_id, file_size)
            await report_repository.update_status(db, report_id, "completed")

            await db.commit()

        except Exception as e:
            await db.rollback()
            await report_repository.update_status(db, report_id, "failed")
            await db.commit()
            raise


@celery_app.task(
    bind=True,
    max_retries=3,
    default_retry_delay=60,
    time_limit=300,
    soft_time_limit=240,
)
def generate_csv_report(
    self,
    scenario_id: str,
    report_id: str,
    include_logs: bool = True,
    date_from: str = None,
    date_to: str = None,
):
    """Generate CSV report asynchronously.

    Args:
        scenario_id: Scenario UUID string
        report_id: Report UUID string
        include_logs: Whether to include log entries
        date_from: Optional start date (ISO format)
        date_to: Optional end date (ISO format)
    """
    correlation_id = set_correlation_id()
    start_time = datetime.utcnow()

    logger.info(
        "Starting CSV report generation",
        extra={
            "scenario_id": scenario_id,
            "report_id": report_id,
            "correlation_id": correlation_id,
        },
    )

    try:
        asyncio.run(
            _generate_csv_async(
                scenario_id=UUID(scenario_id),
                report_id=UUID(report_id),
                include_logs=include_logs,
                date_from=datetime.fromisoformat(date_from) if date_from else None,
                date_to=datetime.fromisoformat(date_to) if date_to else None,
            )
        )

        duration = (datetime.utcnow() - start_time).total_seconds()
        metrics.observe_histogram(
            "reports_generation_duration_seconds",
            duration,
            labels={"format": "csv"},
        )
        metrics.increment_counter(
            "reports_generated_total",
            labels={"format": "csv"},
        )

        logger.info(
            "CSV report generation completed",
            extra={
                "report_id": report_id,
                "duration_seconds": duration,
            },
        )

        return {
            "status": "completed",
            "report_id": report_id,
            "duration_seconds": duration,
        }

    except SoftTimeLimitExceeded:
        logger.error(f"CSV generation timed out for report {report_id}")
        raise self.retry(exc=Exception("Generation timed out"), countdown=120)

    except Exception as exc:
        logger.exception(f"CSV generation failed for report {report_id}")
        raise self.retry(exc=exc, countdown=60)


async def _generate_csv_async(
    scenario_id: UUID,
    report_id: UUID,
    include_logs: bool = True,
    date_from: datetime = None,
    date_to: datetime = None,
):
    """Async helper for CSV generation."""
    async with AsyncSessionLocal() as db:
        try:
            await report_repository.update_status(db, report_id, "processing")

            file_path = await report_service.generate_csv(
                db=db,
                scenario_id=scenario_id,
                report_id=report_id,
                include_logs=include_logs,
                date_from=date_from,
                date_to=date_to,
            )

            file_size = file_path.stat().st_size
            await report_repository.update_file_size(db, report_id, file_size)
            await report_repository.update_status(db, report_id, "completed")

            await db.commit()

        except Exception as e:
            await db.rollback()
            await report_repository.update_status(db, report_id, "failed")
            await db.commit()
            raise
