# -*- 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 SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    # ==========================================================================
    # PARENT FIELD FOR VISIBILITY (used by Studio conditions)
    # ==========================================================================
    x_fc_is_adp_sale = fields.Boolean(
        compute='_compute_is_adp_sale_line',
        string='Is ADP Sale',
        store=False,
        help='True if parent order is an ADP sale - used for column visibility',
    )

    def _compute_is_adp_sale_line(self):
        """Check if parent order is an ADP sale."""
        for line in self:
            is_adp = False
            if line.order_id and line.order_id.x_fc_sale_type:
                is_adp = 'adp' in str(line.order_id.x_fc_sale_type).lower()
            line.x_fc_is_adp_sale = is_adp

    @api.depends('product_id', 'product_id.default_code')
    def _compute_adp_device_type(self):
        """Compute ADP device type and build type from the product's device code."""
        ADPDevice = self.env['fusion.adp.device.code'].sudo()
        for line in self:
            device_type = ''
            build_type = False
            if line.product_id:
                # Get the device code from product (default_code or custom field)
                device_code = line._get_adp_device_code()
                if device_code:
                    # Look up device type in ADP database
                    adp_device = ADPDevice.search([
                        ('device_code', '=', device_code),
                        ('active', '=', True)
                    ], limit=1)
                    if adp_device:
                        device_type = adp_device.device_type or ''
                        build_type = adp_device.build_type or False
            line.x_fc_adp_device_type = device_type
            line.x_fc_adp_build_type = build_type

    # ==========================================================================
    # 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',
        compute='_compute_adp_device_type',
        store=True,
        help='Device type from ADP mobility manual (for approval matching)',
    )
    x_fc_adp_build_type = fields.Selection(
        selection=[
            ('modular', 'Modular'),
            ('custom_fabricated', 'Custom Fabricated'),
        ],
        string='Build Type',
        compute='_compute_adp_device_type',
        store=True,
        help='Build type from ADP mobility manual (Modular or Custom Fabricated)',
    )

    # ==========================================================================
    # COMPUTED ADP PORTIONS
    # ==========================================================================
    x_fc_adp_portion = fields.Monetary(
        string='ADP Portion',
        compute='_compute_adp_portions',
        store=True,
        currency_field='currency_id',
        help='ADP portion for this line',
    )
    x_fc_client_portion = fields.Monetary(
        string='Client Portion',
        compute='_compute_adp_portions',
        store=True,
        currency_field='currency_id',
        help='Client portion for this line',
    )

    # ==========================================================================
    # COMPUTE ADP PORTIONS WITH DEDUCTIONS AND APPROVAL STATUS
    # ==========================================================================
    @api.depends('price_subtotal', 'product_uom_qty', 'price_unit', 'product_id',
                 'order_id.x_fc_sale_type', 'order_id.x_fc_client_type',
                 'order_id.x_fc_device_verification_complete',
                 'x_fc_deduction_type', 'x_fc_deduction_value', 'x_fc_adp_max_price',
                 'x_fc_adp_approved')
    def _compute_adp_portions(self):
        """Compute ADP and client portions based on product's ADP price, client type, and approval status.
        
        IMPORTANT:
        1. If a product has NON-ADP code (NON-ADP, NON-FUNDED, etc.): Client pays 100%
        2. If a product is NOT in the ADP device database: Client pays 100%
        3. If a device is NOT approved by ADP: Client pays 100%
        4. Only products with valid ADP codes that are approved get the 75%/25% (or 100%/0%) split
        """
        ADPDevice = self.env['fusion.adp.device.code'].sudo()
        
        for line in self:
            # Get sale type and client type from parent order
            order = line.order_id
            if not order:
                line.x_fc_adp_portion = 0
                line.x_fc_client_portion = 0
                continue

            # Check if this is an ADP sale
            if not order._is_adp_sale():
                line.x_fc_adp_portion = 0
                line.x_fc_client_portion = 0
                continue

            # Skip non-product lines
            if not line.product_id or line.product_uom_qty <= 0:
                line.x_fc_adp_portion = 0
                line.x_fc_client_portion = 0
                continue

            # =================================================================
            # CHECK 1: Is this a NON-ADP funded product?
            # Products with NON-ADP, NON-FUNDED, UNFUNDED codes = 100% client
            # =================================================================
            if line.product_id.is_non_adp_funded():
                line.x_fc_adp_portion = 0
                line.x_fc_client_portion = line.price_subtotal
                continue

            # =================================================================
            # CHECK 2: Does this product have a valid ADP device code?
            # Products without valid ADP codes in the database = 100% client
            # =================================================================
            device_code = line._get_adp_device_code()
            is_adp_device = False
            if device_code:
                # Check if this code exists in the ADP mobility manual database
                is_adp_device = ADPDevice.search_count([
                    ('device_code', '=', device_code), 
                    ('active', '=', True)
                ]) > 0
            
            # If product has NO valid ADP code in database: client pays 100%
            if not is_adp_device:
                line.x_fc_adp_portion = 0
                line.x_fc_client_portion = line.price_subtotal
                continue
            
            # =================================================================
            # CHECK 3: If this is an ADP device but NOT approved: 100% client
            # =================================================================
            if order.x_fc_device_verification_complete and not line.x_fc_adp_approved:
                line.x_fc_adp_portion = 0
                line.x_fc_client_portion = line.price_subtotal
                continue

            # =================================================================
            # STANDARD CALCULATION: Product is a valid, approved ADP device
            # =================================================================
            
            # Get client type and determine base percentages
            client_type = order._get_client_type()
            if client_type == 'REG':
                # REG: 75% ADP, 25% Client
                base_adp_pct = 0.75
                base_client_pct = 0.25
            else:
                # ODS, OWP, ACS, LTC, SEN, CCA: 100% ADP, 0% Client
                base_adp_pct = 1.0
                base_client_pct = 0.0

            # Get the ADP price from the product
            adp_price = 0
            if line.product_id and line.product_id.product_tmpl_id:
                product_tmpl = line.product_id.product_tmpl_id
                if hasattr(product_tmpl, 'x_fc_adp_price'):
                    adp_price = product_tmpl.x_fc_adp_price or 0
                if not adp_price and line.x_fc_adp_max_price:
                    adp_price = line.x_fc_adp_max_price
                if not adp_price:
                    adp_price = line.price_unit

            qty = line.product_uom_qty
            adp_base_total = adp_price * qty

            # Apply deductions
            if line.x_fc_deduction_type == 'pct' and line.x_fc_deduction_value:
                # PCT: ADP only covers deduction_value% of their portion
                effective_adp_pct = base_adp_pct * (line.x_fc_deduction_value / 100)
                effective_client_pct = 1 - effective_adp_pct
                adp_portion = adp_base_total * effective_adp_pct
                client_portion = adp_base_total * effective_client_pct
            elif line.x_fc_deduction_type == 'amt' and line.x_fc_deduction_value:
                # AMT: Subtract fixed amount from ADP portion
                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:
                # No deduction - standard calculation based on ADP price
                adp_portion = adp_base_total * base_adp_pct
                client_portion = adp_base_total * base_client_pct

            line.x_fc_adp_portion = adp_portion
            line.x_fc_client_portion = client_portion

    # ==========================================================================
    # GETTER METHODS
    # ==========================================================================
    def _get_adp_device_code(self):
        """Get ADP device code from product.
        
        Checks multiple sources in order:
        1. x_fc_adp_device_code (module field)
        2. x_adp_code (Studio/custom field)
        3. default_code
        4. Code in parentheses in product name (e.g., "Product Name (SE0001109)")
        """
        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
        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 ''
        # Find all codes in parentheses
        matches = re.findall(r'\(([A-Z0-9]+)\)', product_name)
        for potential_code in matches:
            if ADPDevice.search_count([('device_code', '=', potential_code), ('active', '=', True)]) > 0:
                return potential_code
        
        # 5. Final fallback - return default_code even if not in ADP database
        return self.product_id.default_code or ''

    def _get_adp_code_for_report(self):
        """Return the ADP device code for display on reports.

        Uses the product's x_fc_adp_device_code field (not default_code).
        Returns 'NON-FUNDED' for non-ADP products.
        """
        self.ensure_one()
        if not self.product_id:
            return 'NON-FUNDED'
        if self.product_id.is_non_adp_funded():
            return 'NON-FUNDED'
        product_tmpl = self.product_id.product_tmpl_id
        code = ''
        if hasattr(product_tmpl, 'x_fc_adp_device_code'):
            code = getattr(product_tmpl, 'x_fc_adp_device_code', '') or ''
        if not code and hasattr(product_tmpl, 'x_adp_code'):
            code = getattr(product_tmpl, 'x_adp_code', '') or ''
        if not code:
            return 'NON-FUNDED'
        ADPDevice = self.env['fusion.adp.device.code'].sudo()
        if ADPDevice.search_count([('device_code', '=', code), ('active', '=', True)]) > 0:
            return code
        return 'NON-FUNDED'

    def _get_adp_device_type(self):
        """Live lookup of device type from the ADP device code table.

        Returns 'No Funding Available' for non-ADP products.
        """
        self.ensure_one()
        if not self.product_id or self.product_id.is_non_adp_funded():
            return 'No Funding Available'
        code = self._get_adp_code_for_report()
        if code == 'NON-FUNDED':
            return 'No Funding Available'
        if self.x_fc_adp_device_type:
            return self.x_fc_adp_device_type
        adp_device = self.env['fusion.adp.device.code'].sudo().search([
            ('device_code', '=', code),
            ('active', '=', True),
        ], limit=1)
        return adp_device.device_type if adp_device else 'No Funding Available'

    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_sol_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'

    # ==========================================================================
    # INVOICE LINE PREPARATION
    # ==========================================================================
    def _prepare_invoice_line(self, **optional_values):
        """Override to copy ADP line fields to the invoice line."""
        vals = super()._prepare_invoice_line(**optional_values)
        vals.update({
            'x_fc_serial_number': self.x_fc_serial_number,
            'x_fc_device_placement': self.x_fc_device_placement,
            'x_fc_deduction_type': self.x_fc_deduction_type,
            'x_fc_deduction_value': self.x_fc_deduction_value,
            'x_fc_adp_max_price': self.x_fc_adp_max_price,
            'x_fc_sn_required': self.x_fc_sn_required,
            'x_fc_adp_approved': self.x_fc_adp_approved,
            'x_fc_adp_device_type': self.x_fc_adp_device_type,
        })
        return vals

    # ==========================================================================
    # ONCHANGE FOR ADP MAX PRICE LOOKUP
    # ==========================================================================
    @api.onchange('product_id')
    def _onchange_product_adp_info(self):
        """Lookup ADP info from device codes when product changes."""
        if self.product_id:
            # Try to find device code in the reference table
            device_code = self._get_adp_device_code()
            if device_code:
                adp_device = self.env['fusion.adp.device.code'].sudo().search([
                    ('device_code', '=', device_code)
                ], limit=1)
                if adp_device:
                    self.x_fc_adp_max_price = adp_device.adp_price
                    self.x_fc_sn_required = adp_device.sn_required
