# -*- coding: utf-8 -*-
# Copyright 2024-2025 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Claim Assistant product family.

import logging
from datetime import date, timedelta
from odoo import models, api

_logger = logging.getLogger(__name__)


class ADPPostingScheduleMixin(models.AbstractModel):
    """Mixin providing ADP posting schedule calculation methods.
    
    This mixin can be inherited by any model that needs to calculate
    ADP posting dates and deadlines.
    
    Posting Schedule Logic:
    - Posting days occur every N days (default 14) from a base date
    - Submission deadline: Wednesday 6 PM before posting day
    - Delivery reminder: Tuesday of posting week
    - Billing reminder: Monday of posting week
    - Payment processed: Posting day + 7 days
    - Payment received: Posting day + 10 days
    """
    _name = 'fusion_claims.adp.posting.schedule.mixin'
    _description = 'ADP Posting Schedule Mixin'

    @api.model
    def _get_adp_posting_base_date(self):
        """Get the configured base posting date from settings."""
        ICP = self.env['ir.config_parameter'].sudo()
        base_date_str = ICP.get_param('fusion_claims.adp_posting_base_date', '2026-01-23')
        try:
            return date.fromisoformat(base_date_str)
        except (ValueError, TypeError):
            return date(2026, 1, 23)

    @api.model
    def _get_adp_posting_frequency(self):
        """Get the configured posting frequency in days from settings."""
        ICP = self.env['ir.config_parameter'].sudo()
        frequency = ICP.get_param('fusion_claims.adp_posting_frequency_days', '14')
        try:
            return int(frequency)
        except (ValueError, TypeError):
            return 14

    @api.model
    def _get_next_posting_date(self, from_date=None):
        """Calculate the next ADP posting date from a given date.
        
        Args:
            from_date: The date to calculate from (default: today)
            
        Returns:
            date: The next posting date
        """
        if from_date is None:
            from_date = date.today()
        elif hasattr(from_date, 'date'):
            from_date = from_date.date()
        
        base_date = self._get_adp_posting_base_date()
        frequency = self._get_adp_posting_frequency()
        
        if frequency <= 0:
            frequency = 14
        
        # Calculate days since base date
        days_diff = (from_date - base_date).days
        
        if days_diff < 0:
            # from_date is before base_date, so base_date is the next posting date
            return base_date
        
        # Calculate how many complete cycles have passed
        cycles_passed = days_diff // frequency
        
        # The next posting date is (cycles_passed + 1) * frequency days from base
        next_posting = base_date + timedelta(days=(cycles_passed + 1) * frequency)
        
        # If from_date equals a posting date, return the next one
        if days_diff % frequency == 0:
            return next_posting
        
        return next_posting

    @api.model
    def _get_current_posting_date(self, from_date=None):
        """Get the posting date for the current cycle (may be in the past).
        
        Args:
            from_date: The date to calculate from (default: today)
            
        Returns:
            date: The current cycle's posting date
        """
        if from_date is None:
            from_date = date.today()
        elif hasattr(from_date, 'date'):
            from_date = from_date.date()
        
        base_date = self._get_adp_posting_base_date()
        frequency = self._get_adp_posting_frequency()
        
        if frequency <= 0:
            frequency = 14
        
        days_diff = (from_date - base_date).days
        
        if days_diff < 0:
            return base_date
        
        cycles_passed = days_diff // frequency
        return base_date + timedelta(days=cycles_passed * frequency)

    @api.model
    def _get_posting_week_wednesday(self, posting_date):
        """Get the Wednesday before the posting date (submission deadline day).
        
        The submission deadline is Wednesday 6 PM of the posting week.
        Posting day is typically Friday, so Wednesday is 2 days before.
        
        Args:
            posting_date: The posting date
            
        Returns:
            date: The Wednesday before posting date
        """
        if hasattr(posting_date, 'date'):
            posting_date = posting_date.date()
        
        # Find the Wednesday of the same week
        # weekday(): Monday=0, Tuesday=1, Wednesday=2, Thursday=3, Friday=4
        days_since_wednesday = (posting_date.weekday() - 2) % 7
        if days_since_wednesday == 0 and posting_date.weekday() != 2:
            days_since_wednesday = 7
        
        return posting_date - timedelta(days=days_since_wednesday)

    @api.model
    def _get_posting_week_tuesday(self, posting_date):
        """Get the Tuesday of the posting week (delivery reminder date).
        
        Args:
            posting_date: The posting date
            
        Returns:
            date: The Tuesday of posting week
        """
        if hasattr(posting_date, 'date'):
            posting_date = posting_date.date()
        
        # Find the Tuesday of the same week
        days_since_tuesday = (posting_date.weekday() - 1) % 7
        if days_since_tuesday == 0 and posting_date.weekday() != 1:
            days_since_tuesday = 7
        
        return posting_date - timedelta(days=days_since_tuesday)

    @api.model
    def _get_posting_week_monday(self, posting_date):
        """Get the Monday of the posting week (billing reminder date).
        
        Args:
            posting_date: The posting date
            
        Returns:
            date: The Monday of posting week
        """
        if hasattr(posting_date, 'date'):
            posting_date = posting_date.date()
        
        # Find the Monday of the same week
        days_since_monday = posting_date.weekday()  # Monday=0
        return posting_date - timedelta(days=days_since_monday)

    @api.model
    def _get_expected_payment_date(self, posting_date):
        """Get the expected payment received date (posting + 10 days).
        
        Args:
            posting_date: The posting date
            
        Returns:
            date: The expected payment received date
        """
        if hasattr(posting_date, 'date'):
            posting_date = posting_date.date()
        
        return posting_date + timedelta(days=10)

    @api.model
    def _get_payment_processed_date(self, posting_date):
        """Get the payment processed date (posting + 7 days).
        
        Args:
            posting_date: The posting date
            
        Returns:
            date: The payment processed date
        """
        if hasattr(posting_date, 'date'):
            posting_date = posting_date.date()
        
        return posting_date + timedelta(days=7)

    @api.model
    def _get_adp_billing_reminder_user(self):
        """Get the configured billing reminder user from settings."""
        ICP = self.env['ir.config_parameter'].sudo()
        user_id_str = ICP.get_param('fusion_claims.adp_billing_reminder_user_id', '')
        if user_id_str:
            try:
                user_id = int(user_id_str)
                return self.env['res.users'].browse(user_id).exists()
            except (ValueError, TypeError):
                pass
        return self.env['res.users']

    @api.model
    def _get_adp_correction_reminder_users(self):
        """Get the configured correction reminder users from settings."""
        ICP = self.env['ir.config_parameter'].sudo()
        user_ids_str = ICP.get_param('fusion_claims.adp_correction_reminder_user_ids', '')
        if user_ids_str:
            try:
                user_ids = [int(x.strip()) for x in user_ids_str.split(',') if x.strip()]
                return self.env['res.users'].browse(user_ids).exists()
            except (ValueError, TypeError):
                pass
        return self.env['res.users']

    @api.model
    def _is_past_submission_deadline(self, posting_date=None, check_time=True):
        """Check if we're past the submission deadline for a posting cycle.
        
        Args:
            posting_date: The posting date to check (default: next posting date)
            check_time: If True, checks if past 6 PM on Wednesday
            
        Returns:
            bool: True if past deadline
        """
        from datetime import datetime
        
        if posting_date is None:
            posting_date = self._get_next_posting_date()
        
        wednesday = self._get_posting_week_wednesday(posting_date)
        today = date.today()
        
        if today > wednesday:
            return True
        elif today == wednesday and check_time:
            # Check if past 6 PM (18:00)
            now = datetime.now()
            return now.hour >= 18
        
        return False
