# -*- 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.

from odoo import models, fields, api


class AccountMoveLine(models.Model):
    _inherit = 'account.move.line'

    # ==========================================================================
    # SERIAL NUMBER AND DEVICE PLACEMENT
    # ==========================================================================
    x_fc_serial_number = fields.Char(
        string='Serial Number',
        help='Serial number for this product',
    )
    x_fc_device_placement = fields.Selection(
        selection=[
            ('L', 'Left'),
            ('R', 'Right'),
            ('NA', 'N/A'),
        ],
        string='Device Placement',
        default='NA',
        help='Device placement position (Left/Right/N/A)',
    )

    # ==========================================================================
    # DEDUCTION FIELDS
    # ==========================================================================
    x_fc_deduction_type = fields.Selection(
        selection=[
            ('none', 'No Deduction'),
            ('pct', 'Percentage'),
            ('amt', 'Amount'),
        ],
        string='Deduction Type',
        default='none',
        help='Type of ADP deduction applied to this line',
    )
    x_fc_deduction_value = fields.Float(
        string='Deduction Value',
        digits='Product Price',
        help='Deduction value (percentage if PCT, dollar amount if AMT)',
    )

    # ==========================================================================
    # ADP REFERENCE FIELDS
    # ==========================================================================
    x_fc_adp_max_price = fields.Float(
        string='ADP Max Price',
        digits='Product Price',
        help='Maximum price ADP will cover for this device (from mobility manual)',
    )
    x_fc_sn_required = fields.Boolean(
        string='S/N Required',
        help='Is serial number required for this device?',
    )
    
    # ==========================================================================
    # ADP DEVICE APPROVAL TRACKING
    # ==========================================================================
    x_fc_adp_approved = fields.Boolean(
        string='ADP Approved',
        default=False,
        help='Was this device approved by ADP in the application approval?',
    )
    x_fc_adp_device_type = fields.Char(
        string='ADP Device Type',
        help='Device type from ADP mobility manual (for approval matching)',
    )

    # ==========================================================================
    # ADP PORTIONS - Stored fields set during invoice creation
    # ==========================================================================
    x_fc_adp_portion = fields.Monetary(
        string='ADP Portion',
        currency_field='currency_id',
        help='ADP portion for this line (calculated during invoice creation from device codes database)',
    )
    x_fc_client_portion = fields.Monetary(
        string='Client Portion',
        currency_field='currency_id',
        help='Client portion for this line (calculated during invoice creation from device codes database)',
    )

    def _compute_adp_portions(self):
        """Compute ADP and client portions based on device codes database.
        
        This is called during invoice type/client type changes to recalculate portions.
        """
        self.action_recalculate_portions()
    
    def action_recalculate_portions(self):
        """Manually recalculate ADP and client portions based on device codes database.
        
        This can be called to recalculate portions if values are incorrect.
        Uses the same logic as invoice creation.
        """
        ADPDevice = self.env['fusion.adp.device.code'].sudo()
        
        for line in self:
            move = line.move_id
            if not move or move.move_type not in ['out_invoice', 'out_refund']:
                continue
            
            if not line.product_id or line.quantity <= 0:
                continue
            
            # Get client type
            client_type = move._get_client_type()
            if client_type == 'REG':
                base_adp_pct = 0.75
                base_client_pct = 0.25
            else:
                base_adp_pct = 1.0
                base_client_pct = 0.0
            
            # Get ADP price from device codes database (priority)
            device_code = line._get_adp_device_code()
            adp_price = 0
            
            if device_code:
                adp_device = ADPDevice.search([
                    ('device_code', '=', device_code),
                    ('active', '=', True)
                ], limit=1)
                if adp_device:
                    adp_price = adp_device.adp_price or 0
            
            # Fallback to product fields
            if not adp_price and line.product_id:
                product_tmpl = line.product_id.product_tmpl_id
                if hasattr(product_tmpl, 'x_fc_adp_price'):
                    adp_price = getattr(product_tmpl, 'x_fc_adp_price', 0) or 0
                # (Studio field fallback removed)
            
            # Fallback to line max price or unit price
            if not adp_price:
                adp_price = line.x_fc_adp_max_price or line.price_unit
            
            qty = line.quantity
            adp_base_total = adp_price * qty
            
            # Apply deductions
            if line.x_fc_deduction_type == 'pct' and line.x_fc_deduction_value:
                effective_adp_pct = base_adp_pct * (line.x_fc_deduction_value / 100)
                adp_portion = adp_base_total * effective_adp_pct
                client_portion = adp_base_total - adp_portion
            elif line.x_fc_deduction_type == 'amt' and line.x_fc_deduction_value:
                base_adp_amount = adp_base_total * base_adp_pct
                adp_portion = max(0, base_adp_amount - line.x_fc_deduction_value)
                client_portion = adp_base_total - adp_portion
            else:
                adp_portion = adp_base_total * base_adp_pct
                client_portion = adp_base_total * base_client_pct
            
            line.write({
                'x_fc_adp_portion': adp_portion,
                'x_fc_client_portion': client_portion,
                'x_fc_adp_max_price': adp_price,
            })

    # ==========================================================================
    # GETTER METHODS
    # ==========================================================================
    def _get_adp_device_code(self):
        """Get ADP device code from product.
        
        Checks multiple sources in order and validates against ADP device database:
        1. x_fc_adp_device_code (module field) - verified in ADP database
        2. x_adp_code (Studio/custom field) - verified in ADP database
        3. default_code - verified in ADP database
        4. Code in parentheses in product name (e.g., "Product Name (SE0001109)")
        
        Returns empty string if no valid ADP code found.
        """
        import re
        
        self.ensure_one()
        if not self.product_id:
            return ''
        
        product_tmpl = self.product_id.product_tmpl_id
        ADPDevice = self.env['fusion.adp.device.code'].sudo()
        
        # 1. Check x_fc_adp_device_code (module field)
        code = ''
        if hasattr(product_tmpl, 'x_fc_adp_device_code'):
            code = getattr(product_tmpl, 'x_fc_adp_device_code', '') or ''
        
        # Verify code exists in ADP database
        if code and ADPDevice.search_count([('device_code', '=', code), ('active', '=', True)]) > 0:
            return code
        
        # 2. Check x_adp_code (Studio/custom field)
        if hasattr(product_tmpl, 'x_adp_code'):
            code = getattr(product_tmpl, 'x_adp_code', '') or ''
            if code and ADPDevice.search_count([('device_code', '=', code), ('active', '=', True)]) > 0:
                return code
        
        # 3. Check default_code - ONLY if it's a valid ADP code
        code = self.product_id.default_code or ''
        if code and ADPDevice.search_count([('device_code', '=', code), ('active', '=', True)]) > 0:
            return code
        
        # 4. Try to extract code from product name in parentheses
        # E.g., "[MXA-1618] GEOMATRIX SILVERBACK MAX BACKREST - ACTIVE (SE0001109)"
        product_name = self.product_id.name or ''
        match = re.search(r'\(([A-Z]{2}\d{7})\)', product_name)
        if match:
            code = match.group(1)
            if ADPDevice.search_count([('device_code', '=', code), ('active', '=', True)]) > 0:
                return code
        
        # 5. Last resort: check if there's a linked sale order line with ADP code
        if self.sale_line_ids:
            for sale_line in self.sale_line_ids:
                if hasattr(sale_line, '_get_adp_device_code'):
                    sale_code = sale_line._get_adp_device_code()
                    if sale_code:
                        return sale_code
        
        # No valid ADP code found - return empty to skip this line in export
        return ''

    def _get_serial_number(self):
        """Get serial number from mapped field or native field."""
        self.ensure_one()
        ICP = self.env['ir.config_parameter'].sudo()
        field_name = ICP.get_param('fusion_claims.field_aml_serial', 'x_fc_serial_number')
        
        # Try mapped field first
        if hasattr(self, field_name):
            value = getattr(self, field_name, None)
            if value:
                return value
        
        # Fallback to native field
        return self.x_fc_serial_number or ''

    def _get_device_placement(self):
        """Get device placement."""
        self.ensure_one()
        return self.x_fc_device_placement or 'NA'
