# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)

import logging
from email.utils import parseaddr

from odoo import models, fields, api

_logger = logging.getLogger(__name__)


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

    x_fa_created_from_email = fields.Boolean(
        string='Created from Email',
        default=False,
        readonly=True,
        copy=False,
        help='This bill was automatically created from an incoming email.',
    )
    x_fa_match_level = fields.Selection(
        selection=[
            ('exact_email', 'Exact Email'),
            ('domain', 'Domain Match'),
            ('name', 'Name Match'),
            ('no_match', 'No Match'),
        ],
        string='Vendor Match Level',
        readonly=True,
        copy=False,
        help='How the vendor was matched from the sender email.',
    )
    x_fa_ai_extracted = fields.Boolean(
        string='AI Extracted',
        default=False,
        readonly=True,
        copy=False,
        help='Bill data was extracted using AI.',
    )
    x_fa_original_sender = fields.Char(
        string='Original Email Sender',
        readonly=True,
        copy=False,
        help='The original sender email address that triggered bill creation.',
    )

    # =========================================================================
    # VENDOR MATCHING
    # =========================================================================
    @api.model
    def _fa_match_vendor_from_email(self, email_from):
        """Multi-level vendor matching from sender email.

        Tries three levels:
        1. Exact email match
        2. Domain match (email domain or website)
        3. Name match (sender display name)

        Returns: (partner_record, match_level) or (False, 'no_match')
        """
        if not email_from:
            return False, 'no_match'

        # Parse "Display Name <email@example.com>" format
        display_name, email_address = parseaddr(email_from)
        if not email_address:
            return False, 'no_match'

        email_address = email_address.strip().lower()
        Partner = self.env['res.partner'].sudo()

        # Check settings for which match levels are enabled
        ICP = self.env['ir.config_parameter'].sudo()
        enable_domain = ICP.get_param('fusion_accounts.enable_domain_match', 'True') == 'True'
        enable_name = ICP.get_param('fusion_accounts.enable_name_match', 'True') == 'True'

        # ----- Level 1: Exact email match -----
        partner = Partner.search([
            ('email', '=ilike', email_address),
            ('supplier_rank', '>', 0),
        ], limit=1)
        if not partner:
            # Also check without supplier_rank filter (contact might not be flagged as vendor)
            partner = Partner.search([
                ('email', '=ilike', email_address),
            ], limit=1)

        if partner:
            _logger.info("Vendor match Level 1 (exact email): %s -> %s",
                         email_address, partner.name)
            return partner, 'exact_email'

        # ----- Level 2: Domain match -----
        if enable_domain and '@' in email_address:
            domain = email_address.split('@')[1]
            # Skip common email providers
            common_domains = {
                'gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com',
                'live.com', 'aol.com', 'icloud.com', 'mail.com',
                'protonmail.com', 'zoho.com',
            }
            if domain not in common_domains:
                # Search by email domain
                partners = Partner.search([
                    '|',
                    ('email', '=ilike', f'%@{domain}'),
                    ('website', 'ilike', domain),
                ])
                if partners:
                    # Prefer is_company=True (the parent company)
                    company_partner = partners.filtered(lambda p: p.is_company)
                    partner = company_partner[0] if company_partner else partners[0]
                    _logger.info("Vendor match Level 2 (domain): %s -> %s (from %d candidates)",
                                 domain, partner.name, len(partners))
                    return partner, 'domain'

        # ----- Level 3: Name match -----
        if enable_name and display_name:
            clean_name = display_name.strip().strip('"').strip("'")
            if len(clean_name) >= 3:  # Only match names with 3+ characters
                partners = Partner.search([
                    '|',
                    ('name', 'ilike', clean_name),
                    ('commercial_company_name', 'ilike', clean_name),
                ])
                if len(partners) == 1:
                    _logger.info("Vendor match Level 3 (name): '%s' -> %s",
                                 clean_name, partners.name)
                    return partners, 'name'
                elif len(partners) > 1:
                    _logger.info("Vendor match Level 3 skipped: '%s' matched %d partners (ambiguous)",
                                 clean_name, len(partners))

        _logger.info("No vendor match found for: %s (%s)", display_name, email_address)
        return False, 'no_match'

    # =========================================================================
    # MESSAGE_NEW OVERRIDE
    # =========================================================================
    @api.model
    def message_new(self, msg_dict, custom_values=None):
        """Override to add vendor matching and blocking for incoming bills.

        When an email arrives via the accounts alias:
        1. Match sender to a vendor
        2. If vendor is blocked -> log to Discuss, don't create bill
        3. If not blocked -> create draft bill, run AI extraction
        """
        email_from = msg_dict.get('email_from', '') or msg_dict.get('from', '')
        subject = msg_dict.get('subject', '')

        _logger.info("Fusion Accounts: Processing incoming email from '%s' subject '%s'",
                      email_from, subject)

        # Match vendor
        partner, match_level = self._fa_match_vendor_from_email(email_from)

        # Check if vendor is blocked
        if partner and partner.x_fa_block_email_bill:
            _logger.info("Vendor '%s' is blocked for email bill creation. Skipping bill.",
                         partner.name)

            # Log the blocked action
            self.env['fusion.accounts.log'].sudo().create({
                'email_from': email_from,
                'email_subject': subject,
                'email_date': msg_dict.get('date'),
                'vendor_id': partner.id,
                'match_level': match_level,
                'action_taken': 'blocked',
                'notes': f'Vendor "{partner.name}" has email bill creation blocked.',
            })

            # Post note to vendor's chatter
            try:
                partner.message_post(
                    body=f'<p><strong>Blocked bill email:</strong> {subject}</p>'
                         f'<p><strong>From:</strong> {email_from}</p>',
                    message_type='comment',
                    subtype_xmlid='mail.mt_note',
                )
            except Exception as e:
                _logger.warning("Failed to post blocked email to partner chatter: %s", e)

            # Don't create a bill -- just let fetchmail mark the email as handled
            # by raising a controlled exception that fetchmail catches gracefully
            _logger.info("Skipping bill creation for blocked vendor %s", partner.name)
            raise ValueError(
                f"Fusion Accounts: Bill creation blocked for vendor '{partner.name}'. "
                f"Email from {email_from} logged to activity log."
            )

        # Not blocked -- create the bill
        custom_values = custom_values or {}
        custom_values['move_type'] = 'in_invoice'
        if partner:
            custom_values['partner_id'] = partner.id

        # Create the bill via standard Odoo mechanism
        try:
            move = super().message_new(msg_dict, custom_values=custom_values)
            # Write FA fields after creation (Odoo may strip unknown fields from custom_values)
            move.sudo().write({
                'x_fa_created_from_email': True,
                'x_fa_match_level': match_level,
                'x_fa_original_sender': email_from,
            })
        except Exception as e:
            _logger.error("Failed to create bill from email: %s", e)
            self.env['fusion.accounts.log'].sudo().create({
                'email_from': email_from,
                'email_subject': subject,
                'email_date': msg_dict.get('date'),
                'vendor_id': partner.id if partner else False,
                'match_level': match_level,
                'action_taken': 'failed',
                'notes': str(e),
            })
            raise

        # Run AI extraction using attachments from msg_dict
        # (ir.attachment records don't exist yet at this point - they're created by message_post later)
        ai_extracted = False
        ai_result = ''
        try:
            ICP = self.env['ir.config_parameter'].sudo()
            ai_enabled = ICP.get_param('fusion_accounts.ai_enabled', 'True') == 'True'

            if ai_enabled:
                extractor = self.env['fusion.accounts.ai.extractor']
                email_body = msg_dict.get('body', '')

                raw_attachments = msg_dict.get('attachments', [])
                extracted_data = extractor.extract_bill_data_from_raw(
                    email_body, raw_attachments
                )
                if extracted_data:
                    extractor.apply_extracted_data(move, extracted_data)
                    ai_extracted = True
                    ai_result = str(extracted_data)
                    move.sudo().write({'x_fa_ai_extracted': True})

        except Exception as e:
            _logger.warning("AI extraction failed for bill %s: %s", move.id, e)
            ai_result = f'Error: {e}'

        # Log the successful creation
        self.env['fusion.accounts.log'].sudo().create({
            'email_from': email_from,
            'email_subject': subject,
            'email_date': msg_dict.get('date'),
            'vendor_id': partner.id if partner else False,
            'match_level': match_level,
            'action_taken': 'bill_created',
            'bill_id': move.id,
            'ai_extracted': ai_extracted,
            'ai_result': ai_result,
        })

        _logger.info("Fusion Accounts: Created bill %s from email (vendor=%s, match=%s, ai=%s)",
                      move.name, partner.name if partner else 'None', match_level, ai_extracted)

        return move
