"""
Complete Service Example with Queue Manager.

This example demonstrates a complete service application using the queue system
with daemon management, CLI interface, and web monitoring.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

import sys
import time
from pathlib import Path

from queuemgr.proc_api import (
    proc_queue_system,
    start_proc_queue_system,
    stop_proc_queue_system,
    get_proc_queue_system,
)
from queuemgr.jobs.base import QueueJobBase

# Add the project root to the path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))


class DataProcessorJob(QueueJobBase):
    """Job for processing data files."""

    def __init__(self, job_id: str, params: dict):
        """
        Initialize DataProcessorJob.

        Args:
            job_id: Unique job identifier.
            params: Job parameters.
        """
        super().__init__(job_id, params)
        self.input_file = params.get("input_file")
        self.output_file = params.get("output_file")
        self.process_type = params.get("process_type", "transform")

    def execute(self) -> None:
        """Process the data file."""
        print(f"DataProcessorJob {self.job_id}: Processing {self.input_file}")

        # Simulate data processing
        for i in range(10):
            time.sleep(0.5)
            progress = (i + 1) * 10
            print(f"DataProcessorJob {self.job_id}: Progress {progress}%")

        # Create output file
        if self.output_file:
            Path(self.output_file).parent.mkdir(parents=True, exist_ok=True)
            with open(self.output_file, "w") as f:
                f.write(f"Processed data from {self.input_file}\n")
                f.write(f"Process type: {self.process_type}\n")
                f.write(f"Job ID: {self.job_id}\n")

        print(f"DataProcessorJob {self.job_id}: Completed processing")

    def on_start(self) -> None:
        """Called when job starts."""
        print(f"DataProcessorJob {self.job_id}: Starting data processing...")

    def on_stop(self) -> None:
        """Called when job stops."""
        print(f"DataProcessorJob {self.job_id}: Data processing stopped")

    def on_end(self) -> None:
        """Called when job ends."""
        print(f"DataProcessorJob {self.job_id}: Data processing completed successfully")

    def on_error(self, exc: BaseException) -> None:
        """Called when job encounters an error."""
        print(f"DataProcessorJob {self.job_id}: Error occurred: {exc}")


class ReportGeneratorJob(QueueJobBase):
    """Job for generating reports."""

    def __init__(self, job_id: str, params: dict):
        """
        Initialize ReportGeneratorJob.

        Args:
            job_id: Unique job identifier.
            params: Job parameters.
        """
        super().__init__(job_id, params)
        self.report_type = params.get("report_type", "summary")
        self.data_source = params.get("data_source", "database")
        self.output_format = params.get("output_format", "pdf")

    def execute(self) -> None:
        """Generate the report."""
        print(f"ReportGeneratorJob {self.job_id}: Generating {self.report_type} report")

        # Simulate report generation
        for i in range(5):
            time.sleep(1.0)
            progress = (i + 1) * 20
            print(f"ReportGeneratorJob {self.job_id}: Generating... {progress}%")

        # Create report file
        report_file = f"/tmp/report_{self.job_id}.{self.output_format}"
        with open(report_file, "w") as f:
            f.write(f"Report Type: {self.report_type}\n")
            f.write(f"Data Source: {self.data_source}\n")
            f.write(f"Output Format: {self.output_format}\n")
            f.write(f"Generated by Job: {self.job_id}\n")

        print(f"ReportGeneratorJob {self.job_id}: Report saved to {report_file}")

    def on_start(self) -> None:
        """Called when job starts."""
        print(f"ReportGeneratorJob {self.job_id}: Starting report generation...")

    def on_stop(self) -> None:
        """Called when job stops."""
        print(f"ReportGeneratorJob {self.job_id}: Report generation stopped")

    def on_end(self) -> None:
        """Called when job ends."""
        print(
            f"ReportGeneratorJob {self.job_id}: Report generation completed successfully"
        )

    def on_error(self, exc: BaseException) -> None:
        """Called when job encounters an error."""
        print(f"ReportGeneratorJob {self.job_id}: Error occurred: {exc}")


class NotificationJob(QueueJobBase):
    """Job for sending notifications."""

    def __init__(self, job_id: str, params: dict):
        """
        Initialize NotificationJob.

        Args:
            job_id: Unique job identifier.
            params: Job parameters.
        """
        super().__init__(job_id, params)
        self.recipient = params.get("recipient")
        self.message = params.get("message", "Notification from Queue Manager")
        self.notification_type = params.get("notification_type", "email")

    def execute(self) -> None:
        """Send the notification."""
        print(
            f"NotificationJob {self.job_id}: Sending {self.notification_type} to {self.recipient}"
        )

        # Simulate notification sending
        time.sleep(2.0)

        # Create notification log
        log_file = f"/tmp/notification_{self.job_id}.log"
        with open(log_file, "w") as f:
            f.write(f"Recipient: {self.recipient}\n")
            f.write(f"Type: {self.notification_type}\n")
            f.write(f"Message: {self.message}\n")
            f.write(f"Sent at: {time.time()}\n")

        print(f"NotificationJob {self.job_id}: Notification sent successfully")

    def on_start(self) -> None:
        """Called when job starts."""
        print(f"NotificationJob {self.job_id}: Starting notification...")

    def on_stop(self) -> None:
        """Called when job stops."""
        print(f"NotificationJob {self.job_id}: Notification stopped")

    def on_end(self) -> None:
        """Called when job ends."""
        print(f"NotificationJob {self.job_id}: Notification sent successfully")

    def on_error(self, exc: BaseException) -> None:
        """Called when job encounters an error."""
        print(f"NotificationJob {self.job_id}: Error occurred: {exc}")


class ServiceExample:
    """Example service application."""

    def __init__(self):
        """Initialize the service example."""
        self.output_dir = Path("/tmp/queuemgr_service_example")
        self.output_dir.mkdir(exist_ok=True)

    def run_example(self):
        """Run the complete service example."""
        print("🚀 Queue Manager Service Example")
        print("=" * 50)
        print()

        # Method 1: Using context manager (recommended for services)
        print("📋 Method 1: Service with context manager")
        self._run_with_context_manager()

        print("\n" + "=" * 50)
        print()

        # Method 2: Manual service management
        print("📋 Method 2: Manual service management")
        self._run_manual_management()

        print("\n" + "=" * 50)
        print()

        # Method 3: Batch job processing
        print("📋 Method 3: Batch job processing")
        self._run_batch_processing()

        print("\n✅ Service example completed!")
        print(f"📁 Check output files in: {self.output_dir}")

    def _run_with_context_manager(self):
        """Run example with context manager."""
        with proc_queue_system(
            registry_path=str(self.output_dir / "service_registry.jsonl"),
            proc_dir=str(self.output_dir / "proc"),
        ) as queue:
            print("🔧 Service started with context manager")

            # Add various jobs
            jobs = [
                (
                    DataProcessorJob,
                    "data-1",
                    {
                        "input_file": "/tmp/input1.csv",
                        "output_file": str(self.output_dir / "processed1.txt"),
                        "process_type": "transform",
                    },
                ),
                (
                    ReportGeneratorJob,
                    "report-1",
                    {
                        "report_type": "monthly",
                        "data_source": "sales_db",
                        "output_format": "pdf",
                    },
                ),
                (
                    NotificationJob,
                    "notify-1",
                    {
                        "recipient": "admin@example.com",
                        "message": "Monthly report is ready",
                        "notification_type": "email",
                    },
                ),
            ]

            # Add jobs to queue
            for job_class, job_id, params in jobs:
                queue.add_job(job_class, job_id, params)
                print(f"➕ Added job: {job_id}")

            # Start jobs
            for _, job_id, _ in jobs:
                queue.start_job(job_id)
                print(f"▶️ Started job: {job_id}")

            # Monitor jobs
            print("\n📊 Monitoring jobs...")
            for i in range(8):
                jobs = queue.list_jobs()
                running = [j for j in jobs if j.get("status") == "RUNNING"]
                print(f"  Status: {len(jobs)} total, {len(running)} running")
                time.sleep(2)

            print("🔧 Service will stop automatically (context manager)")

    def _run_manual_management(self):
        """Run example with manual service management."""

        try:
            # Start service manually
            start_proc_queue_system(
                registry_path=str(self.output_dir / "manual_registry.jsonl"),
                proc_dir=str(self.output_dir / "manual_proc"),
            )
            print("🔧 Service started manually")

            # Get queue instance

            queue = get_proc_queue_system()

            # Add and start a job
            queue.add_job(
                DataProcessorJob,
                "manual-data-1",
                {
                    "input_file": "/tmp/manual_input.csv",
                    "output_file": str(self.output_dir / "manual_processed.txt"),
                    "process_type": "validate",
                },
            )
            queue.start_job("manual-data-1")
            print("➕ Added and started manual job")

            # Wait for completion
            time.sleep(5)

            # Check status
            status = queue.get_job_status("manual-data-1")
            print(f"📊 Job status: {status.get('status', 'unknown')}")

        finally:
            # Stop service manually
            stop_proc_queue_system()
            print("🔧 Service stopped manually")

    def _run_batch_processing(self):
        """Run example with batch job processing."""
        with proc_queue_system(
            registry_path=str(self.output_dir / "batch_registry.jsonl"),
            proc_dir=str(self.output_dir / "batch_proc"),
        ) as queue:
            print("🔧 Service started for batch processing")

            # Create batch of jobs
            batch_jobs = []
            for i in range(5):
                job_id = f"batch-data-{i+1}"
                queue.add_job(
                    DataProcessorJob,
                    job_id,
                    {
                        "input_file": f"/tmp/batch_input_{i+1}.csv",
                        "output_file": str(
                            self.output_dir / f"batch_processed_{i+1}.txt"
                        ),
                        "process_type": "batch_transform",
                    },
                )
                batch_jobs.append(job_id)

            print(f"➕ Added {len(batch_jobs)} batch jobs")

            # Start jobs in batches
            print("▶️ Starting batch 1 (jobs 1-3)...")
            for job_id in batch_jobs[:3]:
                queue.start_job(job_id)

            time.sleep(3)

            print("▶️ Starting batch 2 (jobs 4-5)...")
            for job_id in batch_jobs[3:]:
                queue.start_job(job_id)

            # Monitor all jobs
            print("\n📊 Monitoring batch processing...")
            for i in range(10):
                jobs = queue.list_jobs()
                running = [j for j in jobs if j.get("status") == "RUNNING"]
                completed = [j for j in jobs if j.get("status") == "COMPLETED"]
                print(
                    f"  Batch status: {len(jobs)} total, {len(running)} running, {len(completed)} completed"
                )
                time.sleep(1)

            print("🔧 Batch processing completed")


def main():
    """Main function."""
    example = ServiceExample()
    example.run_example()


if __name__ == "__main__":
    main()
