import difflib
import logging

from odoo import fields, models
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)


class WooProductFetch(models.TransientModel):
    _name = 'woo.product.fetch'
    _description = 'Fetch WooCommerce Products'

    instance_id = fields.Many2one('woo.instance', required=True, string='WooCommerce Instance')
    state = fields.Selection([
        ('draft', 'Ready'),
        ('fetching', 'Fetching...'),
        ('matching', 'Matching...'),
        ('done', 'Complete'),
    ], default='draft')
    total_fetched = fields.Integer(readonly=True)
    auto_matched = fields.Integer(string='Auto-matched (SKU)', readonly=True)
    suggested = fields.Integer(string='Name Suggestions', readonly=True)
    unmatched = fields.Integer(readonly=True)

    def action_fetch(self):
        self.ensure_one()
        instance = self.instance_id
        if not instance:
            raise UserError("Please select a WooCommerce instance.")

        client = instance._get_client()

        # --- Fetch all products (paginated) ---
        self.state = 'fetching'
        all_products = []
        page = 1
        while True:
            batch = client.get_products(page=page, per_page=100)
            if not batch:
                break
            all_products.extend(batch)
            if len(batch) < 100:
                break
            page += 1

        # Expand variable products with their variations
        expanded = []
        for product in all_products:
            expanded.append(product)
            if product.get('type') == 'variable':
                var_page = 1
                while True:
                    variations = client.get_product_variations(
                        product['id'], page=var_page, per_page=100
                    )
                    if not variations:
                        break
                    for var in variations:
                        var['_parent_id'] = product['id']
                        var['_is_variation'] = True
                    expanded.extend(variations)
                    if len(variations) < 100:
                        break
                    var_page += 1

        total_fetched = len(expanded)

        # --- Match products ---
        self.state = 'matching'

        ProductMap = self.env['woo.product.map']
        ProductProduct = self.env['product.product']

        # Pre-load existing maps for this instance to avoid repeated queries
        existing_woo_ids = set(
            ProductMap.search([('instance_id', '=', instance.id)]).mapped('woo_product_id')
        )

        # Pre-load all odoo products with a SKU for fast lookup
        odoo_products_with_sku = ProductProduct.search([('default_code', '!=', False)])
        sku_index = {p.default_code: p for p in odoo_products_with_sku}

        # For name matching, load all product names
        all_odoo_products = ProductProduct.search([])
        odoo_name_list = [(p.name or '', p) for p in all_odoo_products]

        auto_matched = 0
        suggested_count = 0
        unmatched = 0

        for wc_product in expanded:
            woo_id = wc_product.get('id')
            if not woo_id:
                continue

            # Skip already-mapped
            if woo_id in existing_woo_ids:
                continue

            woo_sku = wc_product.get('sku') or ''
            woo_name = wc_product.get('name') or ''
            woo_type = wc_product.get('type', 'simple')
            is_variation = wc_product.get('_is_variation', False)
            parent_id = wc_product.get('_parent_id') or wc_product.get('parent_id') or 0

            map_vals = {
                'instance_id': instance.id,
                'woo_product_id': woo_id,
                'woo_product_name': woo_name,
                'woo_sku': woo_sku,
                'woo_product_type': woo_type if not is_variation else 'variable',
                'is_variation': is_variation,
                'woo_parent_id': parent_id,
                'company_id': instance.company_id.id,
            }

            # a) SKU match
            matched_product = None
            if woo_sku and woo_sku in sku_index:
                matched_product = sku_index[woo_sku]
                map_vals['product_id'] = matched_product.id
                map_vals['state'] = 'mapped'
                auto_matched += 1
            else:
                # b) Name similarity
                if woo_name and odoo_name_list:
                    ratios = [
                        (difflib.SequenceMatcher(None, woo_name.lower(), name.lower()).ratio(), p)
                        for name, p in odoo_name_list
                    ]
                    best_ratio, best_product = max(ratios, key=lambda x: x[0])
                    if best_ratio > 0.8:
                        map_vals['product_id'] = best_product.id
                        map_vals['state'] = 'unmapped'
                        suggested_count += 1
                    else:
                        map_vals['state'] = 'unmapped'
                        unmatched += 1
                else:
                    map_vals['state'] = 'unmapped'
                    unmatched += 1

            ProductMap.create(map_vals)

        self.write({
            'total_fetched': total_fetched,
            'auto_matched': auto_matched,
            'suggested': suggested_count,
            'unmatched': unmatched,
            'state': 'done',
        })

        return {
            'type': 'ir.actions.act_window',
            'res_model': self._name,
            'res_id': self.id,
            'view_mode': 'form',
            'target': 'new',
        }

    def action_open_mapping(self):
        self.ensure_one()
        return {
            'type': 'ir.actions.act_window',
            'name': 'Product Mapping',
            'res_model': 'woo.product.map',
            'view_mode': 'list,form',
            'domain': [('instance_id', '=', self.instance_id.id)],
            'target': 'current',
        }
