# -*- 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 odoo import models, fields, api
from odoo.exceptions import ValidationError

_logger = logging.getLogger(__name__)


class ResConfigSettings(models.TransientModel):
    _inherit = 'res.config.settings'

    # =========================================================================
    # COMPANY SETTINGS (Related to res.company)
    # =========================================================================

    fc_store_address_1 = fields.Char(
        related='company_id.x_fc_store_address_1',
        readonly=False,
        string='Store Address Line 1',
    )
    fc_store_address_2 = fields.Char(
        related='company_id.x_fc_store_address_2',
        readonly=False,
        string='Store Address Line 2',
    )
    fc_company_tagline = fields.Char(
        related='company_id.x_fc_company_tagline',
        readonly=False,
        string='Company Tagline',
    )
    fc_etransfer_email = fields.Char(
        related='company_id.x_fc_etransfer_email',
        readonly=False,
        string='E-Transfer Email',
    )
    fc_cheque_payable_to = fields.Char(
        related='company_id.x_fc_cheque_payable_to',
        readonly=False,
        string='Cheque Payable To',
    )
    fc_payment_terms_html = fields.Html(
        related='company_id.x_fc_payment_terms_html',
        readonly=False,
        string='Payment Terms',
    )
    fc_include_refund_page = fields.Boolean(
        related='company_id.x_fc_include_refund_page',
        readonly=False,
        string='Include Refund Policy Page',
    )
    fc_refund_policy_html = fields.Html(
        related='company_id.x_fc_refund_policy_html',
        readonly=False,
        string='Refund Policy',
    )

    # =========================================================================
    # ADP BILLING SETTINGS
    # =========================================================================

    fc_vendor_code = fields.Char(
        string='ADP Vendor Code',
        config_parameter='fusion_claims.vendor_code',
        help='Your ADP vendor/location code for claim submissions',
    )

    # =========================================================================
    # FIELD MAPPINGS
    # =========================================================================

    fc_field_sale_type = fields.Char(
        string='Sale Type Field',
        config_parameter='fusion_claims.field_sale_type',
        help='Field name for sale type on sale.order',
    )
    fc_field_so_client_type = fields.Char(
        string='SO Client Type Field',
        config_parameter='fusion_claims.field_so_client_type',
        help='Field name for client type on sale.order',
    )
    fc_field_so_authorizer = fields.Char(
        string='SO Authorizer Field',
        config_parameter='fusion_claims.field_so_authorizer',
        help='Field name for authorizer on sale.order',
    )
    fc_field_invoice_type = fields.Char(
        string='Invoice Type Field',
        config_parameter='fusion_claims.field_invoice_type',
        help='Field name for invoice type on account.move',
    )
    fc_field_inv_client_type = fields.Char(
        string='Invoice Client Type Field',
        config_parameter='fusion_claims.field_inv_client_type',
        help='Field name for client type on account.move',
    )
    fc_field_inv_authorizer = fields.Char(
        string='Invoice Authorizer Field',
        config_parameter='fusion_claims.field_inv_authorizer',
        help='Field name for authorizer on account.move',
    )
    fc_field_product_code = fields.Char(
        string='Product ADP Code Field',
        config_parameter='fusion_claims.field_product_code',
        help='Field name for ADP device code on product.template',
    )
    fc_field_sol_serial = fields.Char(
        string='SO Line Serial Field',
        config_parameter='fusion_claims.field_sol_serial',
        help='Field name for serial number on sale.order.line',
    )
    fc_field_aml_serial = fields.Char(
        string='Invoice Line Serial Field',
        config_parameter='fusion_claims.field_aml_serial',
        help='Field name for serial number on account.move.line',
    )

    # =========================================================================
    # ADDITIONAL SALE ORDER FIELD MAPPINGS
    # =========================================================================
    
    fc_field_so_claim_number = fields.Char(
        string='SO Claim Number Field',
        config_parameter='fusion_claims.field_so_claim_number',
        help='Field name for claim number on sale.order',
    )
    fc_field_so_client_ref_1 = fields.Char(
        string='SO Client Ref 1 Field',
        config_parameter='fusion_claims.field_so_client_ref_1',
        help='Field name for client reference 1 on sale.order',
    )
    fc_field_so_client_ref_2 = fields.Char(
        string='SO Client Ref 2 Field',
        config_parameter='fusion_claims.field_so_client_ref_2',
        help='Field name for client reference 2 on sale.order',
    )
    fc_field_so_delivery_date = fields.Char(
        string='SO Delivery Date Field',
        config_parameter='fusion_claims.field_so_delivery_date',
        help='Field name for ADP delivery date on sale.order',
    )
    fc_field_so_adp_status = fields.Char(
        string='SO ADP Status Field',
        config_parameter='fusion_claims.field_so_adp_status',
        help='Field name for ADP status on sale.order',
    )
    fc_field_so_service_start = fields.Char(
        string='SO Service Start Date Field',
        config_parameter='fusion_claims.field_so_service_start',
        help='Field name for service start date on sale.order',
    )
    fc_field_so_service_end = fields.Char(
        string='SO Service End Date Field',
        config_parameter='fusion_claims.field_so_service_end',
        help='Field name for service end date on sale.order',
    )

    # =========================================================================
    # ADDITIONAL INVOICE FIELD MAPPINGS
    # =========================================================================
    
    fc_field_inv_claim_number = fields.Char(
        string='Invoice Claim Number Field',
        config_parameter='fusion_claims.field_inv_claim_number',
        help='Field name for claim number on account.move',
    )
    fc_field_inv_client_ref_1 = fields.Char(
        string='Invoice Client Ref 1 Field',
        config_parameter='fusion_claims.field_inv_client_ref_1',
        help='Field name for client reference 1 on account.move',
    )
    fc_field_inv_client_ref_2 = fields.Char(
        string='Invoice Client Ref 2 Field',
        config_parameter='fusion_claims.field_inv_client_ref_2',
        help='Field name for client reference 2 on account.move',
    )
    fc_field_inv_delivery_date = fields.Char(
        string='Invoice Delivery Date Field',
        config_parameter='fusion_claims.field_inv_delivery_date',
        help='Field name for ADP delivery date on account.move',
    )
    fc_field_inv_service_start = fields.Char(
        string='Invoice Service Start Date Field',
        config_parameter='fusion_claims.field_inv_service_start',
        help='Field name for service start date on account.move',
    )
    fc_field_inv_service_end = fields.Char(
        string='Invoice Service End Date Field',
        config_parameter='fusion_claims.field_inv_service_end',
        help='Field name for service end date on account.move',
    )

    # =========================================================================
    # SALE ORDER LINE FIELD MAPPINGS
    # =========================================================================
    
    fc_field_sol_placement = fields.Char(
        string='SO Line Placement Field',
        config_parameter='fusion_claims.field_sol_placement',
        help='Field name for device placement on sale.order.line',
    )

    # =========================================================================
    # INVOICE LINE FIELD MAPPINGS
    # =========================================================================
    
    fc_field_aml_placement = fields.Char(
        string='Invoice Line Placement Field',
        config_parameter='fusion_claims.field_aml_placement',
        help='Field name for device placement on account.move.line',
    )

    # =========================================================================
    # PRODUCT FIELD MAPPINGS
    # =========================================================================
    
    fc_field_product_adp_price = fields.Char(
        string='Product ADP Price Field',
        config_parameter='fusion_claims.field_product_adp_price',
        help='Field name for ADP price on product.template',
    )

    # =========================================================================
    # HEADER-LEVEL SERIAL NUMBER MAPPINGS
    # =========================================================================
    
    fc_field_so_primary_serial = fields.Char(
        string='SO Primary Serial Field',
        config_parameter='fusion_claims.field_so_primary_serial',
        help='Field name for primary serial number on sale.order (header level)',
    )
    fc_field_inv_primary_serial = fields.Char(
        string='Invoice Primary Serial Field',
        config_parameter='fusion_claims.field_inv_primary_serial',
        help='Field name for primary serial number on account.move (header level)',
    )

    # =========================================================================
    # ADP POSTING SCHEDULE SETTINGS
    # =========================================================================

    fc_adp_posting_base_date = fields.Char(
        string='ADP Posting Base Date',
        config_parameter='fusion_claims.adp_posting_base_date',
        help='Reference date for calculating bi-weekly posting schedule (a known posting day). Format: YYYY-MM-DD',
    )
    fc_adp_posting_frequency_days = fields.Integer(
        string='Posting Frequency (Days)',
        config_parameter='fusion_claims.adp_posting_frequency_days',
        help='Number of days between ADP posting cycles (typically 14 days)',
    )
    fc_adp_billing_reminder_user_id = fields.Many2one(
        'res.users',
        string='Billing Deadline Reminder Person',
        # NOTE: stored manually via get_values/set_values (not config_parameter)
        # because Many2one + config_parameter causes double-write conflicts
        help='Person to remind on Monday to complete ADP billing by Wednesday 6 PM',
    )
    fc_adp_correction_reminder_user_ids = fields.Many2many(
        'res.users',
        'fc_config_correction_reminder_users_rel',
        'config_id',
        'user_id',
        string='Correction Alert Recipients',
        help='People to notify when an ADP invoice needs correction/resubmission',
    )

    # =========================================================================
    # EMAIL NOTIFICATION SETTINGS
    # =========================================================================

    fc_enable_email_notifications = fields.Boolean(
        string='Enable Automated Email Notifications',
        config_parameter='fusion_claims.enable_email_notifications',
        help='Enable/disable automated email notifications for ADP workflow events',
    )
    fc_office_notification_ids = fields.Many2many(
        related='company_id.x_fc_office_notification_ids',
        readonly=False,
        string='Office Notification Recipients',
    )
    fc_application_reminder_days = fields.Integer(
        string='First Reminder Days',
        config_parameter='fusion_claims.application_reminder_days',
        help='Number of days after assessment completion to send first application reminder to therapist',
    )
    fc_application_reminder_2_days = fields.Integer(
        string='Second Reminder Days (After First)',
        config_parameter='fusion_claims.application_reminder_2_days',
        help='Number of days after first reminder to send second application reminder to therapist',
    )
    
    # =========================================================================
    # WORKFLOW LOCK SETTINGS
    # =========================================================================
    
    fc_allow_sale_type_override = fields.Boolean(
        string='Allow Sale Type Override',
        config_parameter='fusion_claims.allow_sale_type_override',
        help='If enabled, allows changing Sale Type even after application is submitted (for cases where additional benefits are discovered)',
    )
    
    fc_allow_document_lock_override = fields.Boolean(
        string='Allow Document Lock Override',
        config_parameter='fusion_claims.allow_document_lock_override',
        help='When enabled, users in the "Document Lock Override" group can edit locked documents on old cases. '
             'Disable this once all legacy cases have been processed to enforce strict workflow.',
    )
    
    fc_designated_vendor_signer = fields.Many2one(
        'res.users',
        string='Designated Vendor Signer',
        help='The user who signs Page 12 on behalf of the company',
    )

    # ------------------------------------------------------------------
    # AI CLIENT INTELLIGENCE
    # ------------------------------------------------------------------
    fc_ai_api_key = fields.Char(
        string='AI API Key',
        config_parameter='fusion_claims.ai_api_key',
        help='OpenAI API key for Client Intelligence chat',
    )
    fc_ai_model = fields.Selection([
        ('gpt-4o-mini', 'GPT-4o Mini (Fast, Lower Cost)'),
        ('gpt-4o', 'GPT-4o (Best Quality)'),
        ('gpt-4.1-mini', 'GPT-4.1 Mini'),
        ('gpt-4.1', 'GPT-4.1'),
    ], string='AI Model',
        config_parameter='fusion_claims.ai_model',
    )
    fc_auto_parse_xml = fields.Boolean(
        string='Auto-Parse XML Files',
        config_parameter='fusion_claims.auto_parse_xml',
        help='Automatically parse ADP XML files when uploaded and create/update client profiles',
    )

    # ------------------------------------------------------------------
    # TWILIO SMS SETTINGS
    # ------------------------------------------------------------------
    fc_twilio_enabled = fields.Boolean(
        string='Enable Twilio SMS',
        config_parameter='fusion_claims.twilio_enabled',
        help='Enable SMS notifications via Twilio for assessment bookings and key status updates',
    )
    fc_twilio_account_sid = fields.Char(
        string='Twilio Account SID',
        config_parameter='fusion_claims.twilio_account_sid',
        groups='fusion_claims.group_fusion_claims_manager',
    )
    fc_twilio_auth_token = fields.Char(
        string='Twilio Auth Token',
        config_parameter='fusion_claims.twilio_auth_token',
        groups='fusion_claims.group_fusion_claims_manager',
    )
    fc_twilio_phone_number = fields.Char(
        string='Twilio Phone Number',
        config_parameter='fusion_claims.twilio_phone_number',
        help='Your Twilio phone number for sending SMS (e.g. +1234567890)',
    )

    # ------------------------------------------------------------------
    # MARCH OF DIMES SETTINGS
    # ------------------------------------------------------------------
    fc_mod_default_email = fields.Char(
        string='MOD Default Email',
        config_parameter='fusion_claims.mod_default_email',
        help='Default email for sending quotations and documents to March of Dimes (e.g. hvmp@marchofdimes.ca)',
    )
    fc_mod_vendor_code = fields.Char(
        string='March of Dimes Vendor Code',
        config_parameter='fusion_claims.mod_vendor_code',
        help='Your vendor code assigned by March of Dimes (e.g. TRD0001234)',
    )

    # ------------------------------------------------------------------
    # MOD FOLLOW-UP SETTINGS
    # ------------------------------------------------------------------
    fc_mod_followup_interval_days = fields.Integer(
        string='Follow-up Interval (Days)',
        config_parameter='fusion_claims.mod_followup_interval_days',
        help='Number of days between follow-up reminders for MOD cases awaiting funding (default: 14)',
    )
    fc_mod_followup_escalation_days = fields.Integer(
        string='Escalation Delay (Days)',
        config_parameter='fusion_claims.mod_followup_escalation_days',
        help='Days after a follow-up activity is due before auto-sending email to client (default: 3)',
    )

    # ------------------------------------------------------------------
    # ODSP CONFIGURATION
    # ------------------------------------------------------------------
    fc_sa_mobility_email = fields.Char(
        string='SA Mobility Email',
        config_parameter='fusion_claims.sa_mobility_email',
        help='Email address for SA Mobility submissions (default: samobility@ontario.ca)',
    )
    fc_sa_mobility_phone = fields.Char(
        string='SA Mobility Phone',
        config_parameter='fusion_claims.sa_mobility_phone',
        help='SA Mobility phone number (default: 1-888-222-5099)',
    )
    fc_odsp_default_office_id = fields.Many2one(
        'res.partner',
        string='Default ODSP Office',
        domain="[('x_fc_contact_type', '=', 'odsp_office')]",
        help='Default ODSP office contact for new ODSP cases',
    )

    # =========================================================================
    # PORTAL BRANDING
    # =========================================================================

    fc_portal_gradient_preset = fields.Selection([
        ('green_teal', 'Green to Teal (Default)'),
        ('blue_purple', 'Blue to Purple'),
        ('orange_red', 'Sunset Orange'),
        ('dark_slate', 'Dark Slate'),
        ('custom', 'Custom'),
    ],
        string='Portal Gradient Theme',
        config_parameter='fusion_claims.portal_gradient_preset',
        default='green_teal',
    )
    fc_portal_gradient_start = fields.Char(
        string='Gradient Start Color',
        config_parameter='fusion_claims.portal_gradient_start',
        default='#5ba848',
    )
    fc_portal_gradient_mid = fields.Char(
        string='Gradient Mid Color',
        config_parameter='fusion_claims.portal_gradient_mid',
        default='#3a8fb7',
    )
    fc_portal_gradient_end = fields.Char(
        string='Gradient End Color',
        config_parameter='fusion_claims.portal_gradient_end',
        default='#2e7aad',
    )
    fc_portal_gradient_preview = fields.Html(
        string='Gradient Preview',
        compute='_compute_portal_gradient_preview',
        sanitize=False,
    )

    @api.onchange('fc_portal_gradient_preset')
    def _onchange_portal_gradient_preset(self):
        preset = self.fc_portal_gradient_preset
        if preset and preset != 'custom' and preset in self.GRADIENT_PRESETS:
            start, mid, end = self.GRADIENT_PRESETS[preset]
            self.fc_portal_gradient_start = start
            self.fc_portal_gradient_mid = mid
            self.fc_portal_gradient_end = end

    @api.depends(
        'fc_portal_gradient_preset',
        'fc_portal_gradient_start',
        'fc_portal_gradient_mid',
        'fc_portal_gradient_end',
    )
    def _compute_portal_gradient_preview(self):
        for rec in self:
            start = rec.fc_portal_gradient_start or '#5ba848'
            mid = rec.fc_portal_gradient_mid or '#3a8fb7'
            end = rec.fc_portal_gradient_end or '#2e7aad'
            gradient = 'linear-gradient(135deg, %s 0%%, %s 60%%, %s 100%%)' % (start, mid, end)
            rec.fc_portal_gradient_preview = (
                '<div style="background: %s; border-radius: 12px; padding: 24px; min-height: 80px;">'
                '<div style="display: flex; align-items: center; color: #fff;">'
                '<div style="flex: 1;">'
                '<h5 style="color: #fff; margin-bottom: 4px;">'
                '<i class="fa fa-hand-peace-o" style="margin-right: 8px;"></i>'
                'Welcome back, Preview User!</h5>'
                '<small style="color: rgba(255,255,255,0.9);">'
                'This is how your portal dashboard header will look.</small>'
                '</div>'
                '<div style="text-align: right;">'
                '<div style="background: rgba(255,255,255,0.2); border-radius: 8px; padding: 8px 12px;">'
                '<small style="display: block; color: rgba(255,255,255,0.8);">Preview</small>'
                '<strong style="color: #fff;">Live</strong>'
                '</div></div></div></div>'
            ) % gradient

    @api.model
    def get_values(self):
        res = super().get_values()
        ICP = self.env['ir.config_parameter'].sudo()
        
        # Get billing reminder user
        billing_user_id = ICP.get_param('fusion_claims.adp_billing_reminder_user_id', False)
        if billing_user_id:
            try:
                res['fc_adp_billing_reminder_user_id'] = int(billing_user_id)
            except (ValueError, TypeError):
                res['fc_adp_billing_reminder_user_id'] = False
        
        # Get correction reminder users (stored as comma-separated IDs)
        correction_user_ids = ICP.get_param('fusion_claims.adp_correction_reminder_user_ids', '')
        if correction_user_ids:
            try:
                user_ids = [int(x.strip()) for x in correction_user_ids.split(',') if x.strip()]
                res['fc_adp_correction_reminder_user_ids'] = [(6, 0, user_ids)]
            except (ValueError, TypeError):
                res['fc_adp_correction_reminder_user_ids'] = [(6, 0, [])]
        
        # Get designated vendor signer
        vendor_signer_id = ICP.get_param('fusion_claims.designated_vendor_signer', False)
        if vendor_signer_id:
            try:
                res['fc_designated_vendor_signer'] = int(vendor_signer_id)
            except (ValueError, TypeError):
                res['fc_designated_vendor_signer'] = False

        # Get default ODSP office
        odsp_office_id = ICP.get_param('fusion_claims.odsp_default_office_id', False)
        if odsp_office_id:
            try:
                res['fc_odsp_default_office_id'] = int(odsp_office_id)
            except (ValueError, TypeError):
                res['fc_odsp_default_office_id'] = False

        return res

    def set_values(self):
        ICP = self.env['ir.config_parameter'].sudo()

        # --- Protect sensitive config_parameter fields from accidental blanking ---
        # These are keys where a blank/default value should NOT overwrite
        # an existing non-empty value (e.g. API keys, user-customized settings).
        _protected_keys = [
            'fusion_claims.ai_api_key',
            'fusion_claims.vendor_code',
            'fusion_claims.ai_model',
            'fusion_claims.adp_posting_base_date',
            'fusion_claims.application_reminder_days',
            'fusion_claims.application_reminder_2_days',
        ]
        # Snapshot existing values BEFORE super().set_values() runs
        _existing = {}
        for key in _protected_keys:
            val = ICP.get_param(key, '')
            if val:
                _existing[key] = val

        super().set_values()

        # Restore any protected values that were blanked by the save
        for key, old_val in _existing.items():
            new_val = ICP.get_param(key, '')
            if not new_val and old_val:
                ICP.set_param(key, old_val)
                _logger.warning(
                    "Settings protection: restored %s (was blanked during save)", key
                )

        # Store billing reminder user (Many2one - manual handling)
        if self.fc_adp_billing_reminder_user_id:
            ICP.set_param('fusion_claims.adp_billing_reminder_user_id', 
                         str(self.fc_adp_billing_reminder_user_id.id))
        # Only clear if explicitly set to empty AND there was no existing value
        elif not ICP.get_param('fusion_claims.adp_billing_reminder_user_id', ''):
            ICP.set_param('fusion_claims.adp_billing_reminder_user_id', '')
        
        # Store correction reminder users as comma-separated IDs
        if self.fc_adp_correction_reminder_user_ids:
            user_ids = ','.join(str(u.id) for u in self.fc_adp_correction_reminder_user_ids)
            ICP.set_param('fusion_claims.adp_correction_reminder_user_ids', user_ids)
        # Only clear if explicitly empty AND no existing value
        elif not ICP.get_param('fusion_claims.adp_correction_reminder_user_ids', ''):
            ICP.set_param('fusion_claims.adp_correction_reminder_user_ids', '')
        
        # Office notification recipients are stored via related field on res.company
        # No need to store in ir.config_parameter
        
        # Store designated vendor signer (Many2one - manual handling)
        if self.fc_designated_vendor_signer:
            ICP.set_param('fusion_claims.designated_vendor_signer', 
                         str(self.fc_designated_vendor_signer.id))
        elif not ICP.get_param('fusion_claims.designated_vendor_signer', ''):
            ICP.set_param('fusion_claims.designated_vendor_signer', '')

        # Store default ODSP office (Many2one - manual handling)
        if self.fc_odsp_default_office_id:
            ICP.set_param('fusion_claims.odsp_default_office_id',
                         str(self.fc_odsp_default_office_id.id))
        elif not ICP.get_param('fusion_claims.odsp_default_office_id', ''):
            ICP.set_param('fusion_claims.odsp_default_office_id', '')

        # Apply gradient preset colors to ICP so the portal reads them
        preset = self.fc_portal_gradient_preset
        if preset and preset != 'custom' and preset in self.GRADIENT_PRESETS:
            start, mid, end = self.GRADIENT_PRESETS[preset]
            ICP.set_param('fusion_claims.portal_gradient_start', start)
            ICP.set_param('fusion_claims.portal_gradient_mid', mid)
            ICP.set_param('fusion_claims.portal_gradient_end', end)

    # =========================================================================
    # ACTION METHODS
    # =========================================================================

    def action_open_field_mapping_wizard(self):
        """Open the field mapping configuration wizard."""
        return {
            'type': 'ir.actions.act_window',
            'name': 'Field Mapping Configuration',
            'res_model': 'fusion_claims.field_mapping_config',
            'view_mode': 'form',
            'target': 'new',
            'context': {},
        }

    # -- Portal Gradient Presets -----------------------------------------------

    GRADIENT_PRESETS = {
        'green_teal': ('#5ba848', '#3a8fb7', '#2e7aad'),
        'blue_purple': ('#4a90d9', '#7b68ee', '#6a5acd'),
        'orange_red': ('#f7971e', '#e44d26', '#c0392b'),
        'dark_slate': ('#2c3e50', '#4a6274', '#34495e'),
    }

    def _apply_gradient_preset(self, preset_key):
        start, mid, end = self.GRADIENT_PRESETS[preset_key]
        self.fc_portal_gradient_preset = preset_key
        self.fc_portal_gradient_start = start
        self.fc_portal_gradient_mid = mid
        self.fc_portal_gradient_end = end

    def action_set_gradient_green_teal(self):
        self._apply_gradient_preset('green_teal')

    def action_set_gradient_blue_purple(self):
        self._apply_gradient_preset('blue_purple')

    def action_set_gradient_orange_red(self):
        self._apply_gradient_preset('orange_red')

    def action_set_gradient_dark_slate(self):
        self._apply_gradient_preset('dark_slate')

    def action_migrate_adp_export_files(self):
        """Migrate ADP export files from Documents app to the new Export Files menu."""
        return self.env['fusion_claims.adp.export.record'].migrate_from_documents()

