"""
Task definitions for rateloader.

Implements task classes for ExportMailer and PriceExport functionality.
These tasks are designed to be executed by the task queue system.
"""

from typing import Any, Optional

from core.task_queue import Task
from core.logger import get_rateloader_logger, get_hotellabexport_logger, get_hotellabpriceexport_logger, get_queue_logger
from features.export_mailer import ExportMailer
from features.price_export import PriceExport
from core.database_schema import DatabaseSchemaManager, execute_sql_schema, validate_database_schema


class ExportMailerTask(Task):
    """
    Task for executing ExportMailer functionality.

    Downloads SQL files, executes queries, generates CSV files, and sends emails.
    """

    def __init__(self):
        """Initialize ExportMailer task."""
        super().__init__(
            name="ExportMailer",
            description="CSV export and email functionality"
        )
        self.rateloader_logger = get_rateloader_logger()
        self.export_logger = get_hotellabexport_logger()
        self.export_mailer: Optional[ExportMailer] = None

    def execute(self) -> bool:
        """
        Execute the ExportMailer task.

        Returns:
            True if task executed successfully, False otherwise
        """
        try:
            self.rateloader_logger.info("Starting ExportMailer task")
            self.export_logger.info("ExportMailer task started")

            # Create ExportMailer instance
            self.export_mailer = ExportMailer()

            # Run the complete ExportMailer process
            success = self.export_mailer.run_export_mailer()

            if success:
                self.result = "ExportMailer completed successfully"
                self.rateloader_logger.info("ExportMailer task completed successfully")
                self.export_logger.info("ExportMailer task completed successfully")
            else:
                self.error_message = "ExportMailer process failed"
                self.rateloader_logger.error("ExportMailer task failed")
                self.export_logger.error("ExportMailer task failed")

            return success

        except Exception as e:
            error_msg = f"Exception in ExportMailer task: {str(e)}"
            self.error_message = error_msg
            self.rateloader_logger.error(error_msg, exc_info=True)
            self.export_logger.error(error_msg, exc_info=True)
            return False

        finally:
            # Clean up resources
            if self.export_mailer:
                try:
                    self.export_mailer.cleanup()
                except Exception as e:
                    self.rateloader_logger.error(f"Error during ExportMailer cleanup: {str(e)}")


class PriceExportTask(Task):
    """
    Task for executing PriceExport functionality.

    Fetches JSON price data from Oracle and posts to HTTP API.
    """

    def __init__(self):
        """Initialize PriceExport task."""
        super().__init__(
            name="PriceExport",
            description="JSON price export to API functionality"
        )
        self.rateloader_logger = get_rateloader_logger()
        self.price_logger = get_hotellabpriceexport_logger()
        self.price_export: Optional[PriceExport] = None

    def execute(self) -> bool:
        """
        Execute the PriceExport task.

        Returns:
            True if task executed successfully, False otherwise
        """
        try:
            self.rateloader_logger.info("Starting PriceExport task")
            self.price_logger.info("PriceExport task started")

            # Create PriceExport instance
            self.price_export = PriceExport()

            # Run the complete price export process
            stats = self.price_export.export_price_range()

            # Check if export was successful
            if stats.get("total_days", 0) > 0 and stats.get("successful_days", 0) > 0:
                success_rate = stats["successful_days"] / stats["total_days"]
                if success_rate >= 0.8:  # Consider 80%+ success rate as success
                    self.result = f"PriceExport completed successfully: {stats['successful_days']}/{stats['total_days']} days"
                    self.rateloader_logger.info(f"PriceExport task completed successfully: {stats}")
                    self.price_logger.info(f"PriceExport task completed successfully: {stats}")
                    return True
                else:
                    self.error_message = f"PriceExport had low success rate: {stats['successful_days']}/{stats['total_days']} days"
                    self.rateloader_logger.warning(f"PriceExport task completed with low success rate: {stats}")
                    self.price_logger.warning(f"PriceExport task completed with low success rate: {stats}")
                    return False
            else:
                self.error_message = "PriceExport failed: no days processed successfully"
                self.rateloader_logger.error("PriceExport task failed: no days processed successfully")
                self.price_logger.error("PriceExport task failed: no days processed successfully")
                return False

        except Exception as e:
            error_msg = f"Exception in PriceExport task: {str(e)}"
            self.error_message = error_msg
            self.rateloader_logger.error(error_msg, exc_info=True)
            self.price_logger.error(error_msg, exc_info=True)
            return False

        finally:
            # Clean up resources
            if self.price_export:
                try:
                    self.price_export.cleanup()
                except Exception as e:
                    self.rateloader_logger.error(f"Error during PriceExport cleanup: {str(e)}")


class DatabaseInitializationTask(Task):
    """
    Task for initializing or updating the database schema.

    Executes SQL schema scripts with proper dependency ordering.
    """

    def __init__(self, sql_file_path: str = "docs/rateloader.sql", validate_only: bool = False):
        """
        Initialize database initialization task.

        Args:
            sql_file_path: Path to the SQL schema file
            validate_only: If True, only validate schema without executing
        """
        super().__init__(
            name="DatabaseInitialization",
            description=f"Database schema initialization from {sql_file_path}"
        )
        self.sql_file_path = sql_file_path
        self.validate_only = validate_only
        self.logger = get_rateloader_logger()
        self.schema_manager: Optional[DatabaseSchemaManager] = None

    def execute(self) -> bool:
        """
        Execute the database initialization task.

        Returns:
            True if task executed successfully, False otherwise
        """
        try:
            self.logger.info(f"Starting database initialization task (validate_only={self.validate_only})")

            # Create schema manager
            self.schema_manager = DatabaseSchemaManager(self.sql_file_path)

            if self.validate_only:
                # Only validate the schema
                validation_results = self.schema_manager.validate_schema()

                if validation_results["valid"]:
                    self.result = "Schema validation successful - all expected objects present"
                    self.logger.info("Database schema validation completed successfully")
                    return True
                else:
                    missing_objects = validation_results["missing_objects"]
                    self.error_message = f"Schema validation failed - missing objects: {', '.join(missing_objects)}"
                    self.logger.error(f"Schema validation failed: {self.error_message}")
                    return False
            else:
                # Execute the schema
                execution_results = self.schema_manager.execute_schema()

                successful = execution_results["successful"]
                failed = execution_results["failed"]
                total = execution_results["total_objects"]

                if failed == 0:
                    self.result = f"Schema execution completed successfully: {successful}/{total} objects created"
                    self.logger.info(f"Database initialization completed successfully: {successful} objects created")
                    return True
                else:
                    errors = execution_results["errors"]
                    error_details = "; ".join([f"{err['object']}: {err['error']}" for err in errors[:5]])  # First 5 errors
                    if len(errors) > 5:
                        error_details += f" ... and {len(errors) - 5} more errors"

                    self.error_message = f"Schema execution failed: {failed}/{total} objects failed. Errors: {error_details}"
                    self.logger.error(f"Database initialization failed: {self.error_message}")
                    return False

        except Exception as e:
            error_msg = f"Exception in database initialization task: {str(e)}"
            self.error_message = error_msg
            self.logger.error(error_msg, exc_info=True)
            return False

        finally:
            # Clean up resources
            if self.schema_manager:
                try:
                    self.schema_manager.disconnect()
                except Exception as e:
                    self.logger.error(f"Error during schema manager cleanup: {str(e)}")


class CustomTask(Task):
    """
    Generic task for executing custom functions.

    Allows running arbitrary functions as tasks in the queue.
    """

    def __init__(self, name: str, func: callable, description: str = "", *args, **kwargs):
        """
        Initialize custom task.

        Args:
            name: Task name
            func: Function to execute
            description: Optional task description
            *args: Function arguments
            **kwargs: Function keyword arguments
        """
        super().__init__(name, description)
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.logger = get_queue_logger()

    def execute(self) -> bool:
        """
        Execute the custom function.

        Returns:
            True if function executed successfully, False otherwise
        """
        try:
            self.logger.info(f"Starting custom task: {self.name}")

            # Execute the function
            result = self.func(*self.args, **self.kwargs)

            # Store result
            self.result = result

            self.logger.info(f"Custom task completed successfully: {self.name}")
            return True

        except Exception as e:
            error_msg = f"Exception in custom task {self.name}: {str(e)}"
            self.error_message = error_msg
            self.logger.error(error_msg, exc_info=True)
            return False


# Factory functions for creating tasks
def create_export_mailer_task() -> ExportMailerTask:
    """
    Create an ExportMailer task.

    Returns:
        ExportMailerTask instance
    """
    return ExportMailerTask()


def create_price_export_task() -> PriceExportTask:
    """
    Create a PriceExport task.

    Returns:
        PriceExportTask instance
    """
    return PriceExportTask()


def create_database_init_task(sql_file_path: str = "docs/rateloader.sql", validate_only: bool = False) -> DatabaseInitializationTask:
    """
    Create a database initialization task.

    Args:
        sql_file_path: Path to the SQL schema file
        validate_only: If True, only validate schema without executing

    Returns:
        DatabaseInitializationTask instance
    """
    return DatabaseInitializationTask(sql_file_path, validate_only)


def create_custom_task(name: str, func: callable, description: str = "", *args, **kwargs) -> CustomTask:
    """
    Create a custom task.

    Args:
        name: Task name
        func: Function to execute
        description: Optional task description
        *args: Function arguments
        **kwargs: Function keyword arguments

    Returns:
        CustomTask instance
    """
    return CustomTask(name, func, description, *args, **kwargs)