# services/orders/app/services/procurement_scheduler_service.py
"""
Procurement Scheduler Service - Daily procurement planning automation
"""

import asyncio
from datetime import datetime, timedelta
from typing import List, Dict, Any
from uuid import UUID
import structlog
from apscheduler.triggers.cron import CronTrigger

from shared.alerts.base_service import BaseAlertService, AlertServiceMixin
from app.services.procurement_service import ProcurementService

logger = structlog.get_logger()


class ProcurementSchedulerService(BaseAlertService, AlertServiceMixin):
    """
    Procurement scheduler service for automated daily procurement planning
    Extends BaseAlertService to use proven scheduling infrastructure
    """
    
    def __init__(self, config):
        super().__init__(config)
        self.procurement_service = None
        
    async def start(self):
        """Initialize scheduler and procurement service"""
        # Initialize base alert service
        await super().start()
        
        logger.info("Procurement scheduler service started", service=self.config.SERVICE_NAME)
    
    def setup_scheduled_checks(self):
        """Configure daily procurement planning jobs"""
        # Daily procurement planning at 6:00 AM
        self.scheduler.add_job(
            func=self.run_daily_procurement_planning,
            trigger=CronTrigger(hour=6, minute=0),
            id="daily_procurement_planning",
            name="Daily Procurement Planning",
            misfire_grace_time=300,
            coalesce=True,
            max_instances=1
        )
        
        # Weekly procurement optimization at 7:00 AM on Mondays
        self.scheduler.add_job(
            func=self.run_weekly_optimization,
            trigger=CronTrigger(day_of_week=0, hour=7, minute=0),
            id="weekly_procurement_optimization", 
            name="Weekly Procurement Optimization",
            misfire_grace_time=600,
            coalesce=True,
            max_instances=1
        )
        
        logger.info("Procurement scheduled jobs configured")
    
    async def run_daily_procurement_planning(self):
        """Execute daily procurement planning for all active tenants"""
        if not self.is_leader:
            logger.debug("Skipping procurement planning - not leader")
            return
            
        try:
            self._checks_performed += 1
            logger.info("Starting daily procurement planning")
            
            # Get active tenants
            active_tenants = await self.get_active_tenants()
            if not active_tenants:
                logger.info("No active tenants found for procurement planning")
                return
            
            # Process each tenant
            processed_tenants = 0
            for tenant_id in active_tenants:
                try:
                    await self.process_tenant_procurement(tenant_id)
                    processed_tenants += 1
                except Exception as e:
                    logger.error("Error processing tenant procurement",
                               tenant_id=str(tenant_id),
                               error=str(e))
            
            logger.info("Daily procurement planning completed",
                       total_tenants=len(active_tenants),
                       processed_tenants=processed_tenants)
                       
        except Exception as e:
            self._errors_count += 1
            logger.error("Daily procurement planning failed", error=str(e))
    
    async def get_active_tenants(self) -> List[UUID]:
        """Override to return test tenant since tenants table is not in orders DB"""
        # For testing, return the known test tenant
        return [UUID('c464fb3e-7af2-46e6-9e43-85318f34199a')]
    
    async def process_tenant_procurement(self, tenant_id: UUID):
        """Process procurement planning for a specific tenant"""
        try:
            # Use default configuration since tenants table is not in orders DB
            planning_days = 7  # Default planning horizon
            
            # Calculate planning date (tomorrow by default)
            planning_date = datetime.now().date() + timedelta(days=1)
            
            # Create procurement service instance and generate plan
            from app.core.database import AsyncSessionLocal
            from app.schemas.procurement_schemas import GeneratePlanRequest
            from decimal import Decimal
            
            async with AsyncSessionLocal() as session:
                procurement_service = ProcurementService(session, self.config)
                
                # Check if plan already exists for this date
                existing_plan = await procurement_service.get_plan_by_date(
                    tenant_id, planning_date
                )
                
                if existing_plan:
                    logger.debug("Procurement plan already exists",
                               tenant_id=str(tenant_id),
                               plan_date=str(planning_date))
                    return
                
                # Generate procurement plan
                request = GeneratePlanRequest(
                    plan_date=planning_date,
                    planning_horizon_days=planning_days,
                    include_safety_stock=True,
                    safety_stock_percentage=Decimal('20.0')
                )
                
                result = await procurement_service.generate_procurement_plan(tenant_id, request)
                plan = result.plan if result.success else None
            
            if plan:
                # Send notification about new plan
                await self.send_procurement_notification(
                    tenant_id, plan, "plan_created"
                )
                
                logger.info("Procurement plan created successfully",
                          tenant_id=str(tenant_id),
                          plan_id=str(plan.id),
                          plan_date=str(planning_date))
            
        except Exception as e:
            logger.error("Error processing tenant procurement",
                        tenant_id=str(tenant_id),
                        error=str(e))
            raise
    
    async def run_weekly_optimization(self):
        """Run weekly procurement optimization"""
        if not self.is_leader:
            logger.debug("Skipping weekly optimization - not leader")
            return
            
        try:
            self._checks_performed += 1
            logger.info("Starting weekly procurement optimization")
            
            active_tenants = await self.get_active_tenants()
            
            for tenant_id in active_tenants:
                try:
                    await self.optimize_tenant_procurement(tenant_id)
                except Exception as e:
                    logger.error("Error in weekly optimization",
                               tenant_id=str(tenant_id),
                               error=str(e))
            
            logger.info("Weekly procurement optimization completed")
            
        except Exception as e:
            self._errors_count += 1
            logger.error("Weekly procurement optimization failed", error=str(e))
    
    async def optimize_tenant_procurement(self, tenant_id: UUID):
        """Optimize procurement planning for a tenant"""
        # Get plans from the last week
        end_date = datetime.now().date()
        start_date = end_date - timedelta(days=7)
        
        # For now, just log the optimization - full implementation would analyze patterns
        logger.info("Processing weekly optimization", 
                   tenant_id=str(tenant_id), 
                   period=f"{start_date} to {end_date}")
        
        # Simple recommendation: if no plans exist, suggest creating one
        recommendations = [{
            "type": "weekly_review",
            "severity": "low", 
            "title": "Revisión Semanal de Compras",
            "message": "Es momento de revisar y optimizar tu planificación de compras semanal.",
            "metadata": {
                "tenant_id": str(tenant_id),
                "week_period": f"{start_date} to {end_date}"
            }
        }]
        
        for recommendation in recommendations:
            await self.publish_item(
                tenant_id, recommendation, item_type='recommendation'
            )
    
    
    async def send_procurement_notification(self, tenant_id: UUID, 
                                          plan, notification_type: str):
        """Send procurement-related notifications"""
        try:
            if notification_type == "plan_created":
                alert_data = {
                    "type": "procurement_plan_created",
                    "severity": "low",
                    "title": "Plan de Compras Creado",
                    "message": f"Nuevo plan de compras generado para {plan.plan_date if plan else 'fecha desconocida'}",
                    "metadata": {
                        "tenant_id": str(tenant_id),
                        "plan_id": str(plan.id) if plan else "unknown",
                        "plan_date": str(plan.plan_date) if plan else "unknown",
                        "auto_generated": getattr(plan, 'auto_generated', True)
                    }
                }
                
                await self.publish_item(tenant_id, alert_data, item_type='alert')
                
        except Exception as e:
            logger.error("Error sending procurement notification",
                        tenant_id=str(tenant_id),
                        notification_type=notification_type,
                        error=str(e))
    
    async def test_procurement_generation(self):
        """Test method to manually trigger procurement planning for testing"""
        test_tenant_id = UUID('c464fb3e-7af2-46e6-9e43-85318f34199a')
        logger.info("Testing procurement plan generation", tenant_id=str(test_tenant_id))
        
        try:
            await self.process_tenant_procurement(test_tenant_id)
            logger.info("Test procurement generation completed successfully")
        except Exception as e:
            logger.error("Test procurement generation failed", error=str(e), tenant_id=str(test_tenant_id))