"""
Weekly Limit Notification Service - Reports weekly/daily limit exceeded events to API

This service reports when daily or weekly limits are exceeded.
Includes daily rate limiting (max once per day per limit type).
"""

import time
import platform
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
from ws_package.log.writer import LogWriter
from ws_package.services.api_request_service import APIRequest
from ws_package.utils.api_log_policy import api_name_from_url
from ws_package.configs import config
from ws_package.entities.user_entity import UserEntity

logger = LogWriter.file(__name__)


class WeeklyLimitNotificationService:
    """
    Service for reporting weekly/daily limit exceeded events to API.
    
    Features:
    - Daily rate limiting (max once per day per limit type)
    - Fail-safe error handling
    - Automatic retry with backoff
    """
    
    def __init__(self):
        self._enabled = True  # Always enabled
        self._api_url = config('application_weekly_limit_notification_url', 'Application') or "https://desktop-api.workstatus.io/api/weekly/limit/notification"
        
        # Daily rate limiting - track separately for daily and weekly limits
        self._last_daily_limit_report_date = None
        self._last_weekly_limit_report_date = None
        self._last_daily_limit_report_timestamp = None
        self._last_weekly_limit_report_timestamp = None
        
        # Device type detection
        self._device_type = self._get_device_type()
    
    def _get_device_type(self) -> str:
        """Get device type string for API"""
        try:
            system = platform.system()
            if system == "Windows":
                return "Windows"
            elif system == "Darwin":
                return "macOS"
            elif system == "Linux":
                return "Linux"
            else:
                return system
        except Exception:
            return "Unknown"
    
    def _get_os_type_caps(self) -> str:
        """Get OS type in caps format (for compatibility)"""
        try:
            system = platform.system()
            if system == "Darwin":
                return "Mac"
            return system.upper()
        except Exception:
            return "UNKNOWN"
    
    def _can_report_today(self, limit_type: str) -> bool:
        """Check if we can report today for the given limit type (daily limit)"""
        try:
            today = datetime.now().date()
            
            if limit_type == "daily":
                last_report_date = self._last_daily_limit_report_date
            elif limit_type == "weekly":
                last_report_date = self._last_weekly_limit_report_date
            else:
                return True  # Unknown type, allow
            
            # If never reported, allow
            if last_report_date is None:
                return True
            
            # If reported today, deny
            if last_report_date == today:
                return False
            
            # If reported on different day, allow
            return True
        except Exception as e:
            logger.debug("Error checking daily limit (allowing report): %s", e)
            return True  # Fail-safe: allow report
    
    def _mark_reported(self, limit_type: str):
        """Mark that we've reported today for the given limit type"""
        try:
            today = datetime.now().date()
            now = time.time()
            
            if limit_type == "daily":
                self._last_daily_limit_report_date = today
                self._last_daily_limit_report_timestamp = now
            elif limit_type == "weekly":
                self._last_weekly_limit_report_date = today
                self._last_weekly_limit_report_timestamp = now
        except Exception:
            pass  # Fail silently
    
    def _parse_time_to_seconds(self, time_str: str) -> Optional[float]:
        """
        Parse time string in format "HH:MM:SS" or "HH:MM" to total seconds.
        Also handles simple number strings (hours).
        
        Args:
            time_str: Time string like "02:26:28" or "9"
        
        Returns:
            Total seconds as float, or None if parsing fails
        """
        try:
            if not time_str:
                return None
            
            # Handle simple number (hours)
            if ':' not in time_str:
                try:
                    hours = float(time_str)
                    return hours * 3600  # Convert hours to seconds
                except ValueError:
                    return None
            
            # Handle time format "HH:MM:SS" or "HH:MM"
            parts = time_str.split(':')
            if len(parts) == 3:
                hours, minutes, seconds = map(float, parts)
                return hours * 3600 + minutes * 60 + seconds
            elif len(parts) == 2:
                hours, minutes = map(float, parts)
                return hours * 3600 + minutes * 60
            else:
                return None
        except Exception as e:
            logger.debug("Error parsing time string '%s': %s", time_str, e)
            return None
    
    def check_limits_exceeded(
        self,
        daily_limit: Optional[str],
        weekly_limit_hours: Optional[str],
        worked_total_hours_today: Optional[str],
        worked_total_hours_week: Optional[str]
    ) -> Dict[str, bool]:
        """
        Check if daily or weekly limits are exceeded.
        
        Args:
            daily_limit: Daily limit in hours (e.g., "9")
            weekly_limit_hours: Weekly limit in hours (e.g., "42")
            worked_total_hours_today: Hours worked today (e.g., "02:26:28")
            worked_total_hours_week: Hours worked this week (e.g., "37:52:58")
        
        Returns:
            Dict with 'daily_exceeded' and 'weekly_exceeded' boolean flags
        """
        result = {
            'daily_exceeded': False,
            'weekly_exceeded': False
        }
        
        try:
            # Check daily limit
            if daily_limit and worked_total_hours_today:
                daily_limit_seconds = self._parse_time_to_seconds(daily_limit)
                worked_today_seconds = self._parse_time_to_seconds(worked_total_hours_today)
                
                if daily_limit_seconds is not None and worked_today_seconds is not None:
                    if worked_today_seconds >= daily_limit_seconds:
                        result['daily_exceeded'] = True
                        logger.info("Daily limit exceeded: %s >= %s hours", worked_total_hours_today, daily_limit)
            
            # Check weekly limit
            if weekly_limit_hours and worked_total_hours_week:
                weekly_limit_seconds = self._parse_time_to_seconds(weekly_limit_hours)
                worked_week_seconds = self._parse_time_to_seconds(worked_total_hours_week)
                
                if weekly_limit_seconds is not None and worked_week_seconds is not None:
                    if worked_week_seconds >= weekly_limit_seconds:
                        result['weekly_exceeded'] = True
                        logger.info("Weekly limit exceeded: %s >= %s hours", worked_total_hours_week, weekly_limit_hours)
        
        except Exception as e:
            logger.error("Error checking limits: %s", e)
        
        return result
    
    async def report_limit_exceeded(
        self,
        user_entity: UserEntity,
        limit_type: str,  # "daily" or "weekly"
        daily_limit: Optional[str] = None,
        weekly_limit_hours: Optional[str] = None,
        worked_total_hours_today: Optional[str] = None,
        worked_total_hours_week: Optional[str] = None,
        limit_action: Optional[str] = None,
        device_id: Optional[str] = None
    ) -> bool:
        """
        Report limit exceeded event to API.
        
        Args:
            user_entity: User entity with org_id, user_id, sd_token
            limit_type: "daily" or "weekly"
            daily_limit: Daily limit in hours
            weekly_limit_hours: Weekly limit in hours
            worked_total_hours_today: Hours worked today
            worked_total_hours_week: Hours worked this week
            limit_action: "just_notify" or "stop_timer"
            device_id: Device ID for API headers
        
        Returns:
            True if reported successfully, False otherwise
        """
        if not self._enabled:
            return False
        
        # Check daily limit for API calls
        if not self._can_report_today(limit_type):
            logger.info("")
            logger.info("-" * 80)
            logger.info("*** %s LIMIT NOTIFICATION SKIPPED - DAILY LIMIT REACHED ***", limit_type.upper())
            logger.info("(Maximum one notification per day - already reported today)")
            logger.info("Limit type: %s", limit_type)
            logger.info("-" * 80)
            logger.info("")
            return False
        
        try:
            # Build payload
            payload = {
                "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "device_type": self._device_type,
                "limit_type": limit_type,
                "daily_limit": daily_limit,
                "weekly_limit": weekly_limit_hours,
                "worked_total_hours_today": worked_total_hours_today,
                "worked_total_hours_week": worked_total_hours_week,
                "limit_action": limit_action,
                "org_id": user_entity.org_id,
                "user_id": user_entity.user_id
            }
            
            # Headers - similar to other APIs
            headers = {
                "SDToken": str(user_entity.sd_token),
                "OrgID": str(user_entity.org_id),
                "UserID": str(user_entity.user_id),
                "DeviceID": device_id or getattr(user_entity, 'device_id', None) or "",
                "Authorization": f"Bearer {user_entity.sd_token}",
                "Content-Type": "application/json",
                "Accept": "application/json",
                "deviceType": self._get_os_type_caps()
            }
            
            # Make API call (synchronous for now)
            api_label = api_name_from_url(self._api_url)
            logger.info(
                "Sending %s limit exceeded notification (limit_type=%s, action=%s)",
                api_label,
                limit_type,
                limit_action,
            )
            
            api_request = APIRequest(url=self._api_url, headers=headers, timeout=10)
            api_request.post(payload)
            
            # Check response
            if api_request.response and api_request.response.status_code == 200:
                logger.info("%s limit notification sent successfully (type=%s)", api_label, limit_type)
                self._mark_reported(limit_type)
                return True
            else:
                status = api_request.response.status_code if api_request.response else "no response"
                logger.warning("%s limit notification failed (type=%s, HTTP=%s)", api_label, limit_type, status)
                return False
                
        except Exception as e:
            logger.error("Error reporting limit exceeded event (fail-safe): %s", e)
            return False  # Fail-safe: return False, don't crash


# Global singleton instance
_weekly_limit_notification_service = None

def get_weekly_limit_notification_service() -> WeeklyLimitNotificationService:
    """Get the global weekly limit notification service instance"""
    global _weekly_limit_notification_service
    if _weekly_limit_notification_service is None:
        _weekly_limit_notification_service = WeeklyLimitNotificationService()
    return _weekly_limit_notification_service

