import base64
import json
import logging

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

from ..lib.ai_service import AIService
from ..lib.image_processor import ImageProcessor

_logger = logging.getLogger(__name__)


class WooProductCreateVariantLine(models.TransientModel):
    _name = 'woo.product.create.variant.line'
    _description = 'Product Creation Variant Line'

    wizard_id = fields.Many2one('woo.product.create.wizard', ondelete='cascade')
    product_id = fields.Many2one('product.product', string='Variant', readonly=True)
    variant_name = fields.Char(string='Variant', readonly=True)
    attribute_values = fields.Char(string='Attributes', readonly=True)
    sku = fields.Char(string='SKU')
    sale_price = fields.Float(string='Price', digits='Product Price')
    cost_price = fields.Float(string='Cost', digits='Product Price')
    image = fields.Binary(string='Image')
    include = fields.Boolean(string='Include', default=True)


class WooProductCreateWizard(models.TransientModel):
    _name = 'woo.product.create.wizard'
    _description = 'Create Product in WooCommerce'

    # Step tracking
    step = fields.Selection([
        ('basic', 'Basic Info'),
        ('images', 'Images'),
        ('content', 'Content & SEO'),
        ('review', 'Review & Create'),
    ], default='basic')

    instance_id = fields.Many2one('woo.instance', required=True, string='WooCommerce Instance')
    odoo_product_id = fields.Many2one('product.product', string='Odoo Product')

    # Step 1: Basic Info
    product_name = fields.Char(string='Product Name (Odoo - CAPS)')
    wc_product_name = fields.Char(string='Product Name (WC - Title Case)')
    odoo_category_id = fields.Many2one('product.category', string='Odoo Category')
    wc_category_id = fields.Integer(string='WC Category ID')
    wc_category_name = fields.Char(string='WC Category', readonly=True)
    sale_price = fields.Float(string='Sale Price', digits='Product Price')
    cost_price = fields.Float(string='Cost Price', digits='Product Price')
    sku = fields.Char(string='Internal Reference / SKU')
    sales_tax_id = fields.Many2one('account.tax', string='Sales Tax',
        domain="[('type_tax_use', '=', 'sale')]")
    purchase_tax_id = fields.Many2one('account.tax', string='Purchase Tax',
        domain="[('type_tax_use', '=', 'purchase')]")
    wc_tax_class = fields.Char(string='WC Tax Class')

    # Step 2: Images
    image_1 = fields.Binary(string='Image 1 (Featured)')
    image_1_filename = fields.Char()
    image_2 = fields.Binary(string='Image 2')
    image_2_filename = fields.Char()
    image_3 = fields.Binary(string='Image 3')
    image_3_filename = fields.Char()
    image_4 = fields.Binary(string='Image 4')
    image_4_filename = fields.Char()
    image_5 = fields.Binary(string='Image 5')
    image_5_filename = fields.Char()

    # Image AI metadata (stored as JSON text)
    image_metadata = fields.Text(string='Image Metadata', default='[]')
    images_geotagged = fields.Boolean(string='Images Geo-tagged')

    # Step 3: Content & SEO
    raw_product_info = fields.Text(string='Product Information',
        help='Type everything you know about this product. The AI will use this to generate descriptions.')
    ai_keywords = fields.Char(string='Keywords')
    wc_title = fields.Char(string='WC Product Title')
    short_description = fields.Html(string='Short Description')
    long_description = fields.Html(string='Long Description')
    meta_title = fields.Char(string='Meta Title')
    meta_description = fields.Text(string='Meta Description')
    seo_keywords = fields.Char(string='SEO Focus Keywords')

    # Variant detection
    has_variants = fields.Boolean(compute='_compute_has_variants')
    variant_count = fields.Integer(compute='_compute_has_variants')
    product_template_id = fields.Many2one('product.template', compute='_compute_has_variants')

    # Variant line display
    variant_line_ids = fields.One2many('woo.product.create.variant.line', 'wizard_id')

    # Step 4 is review - uses fields above

    # --- Variant Detection ---

    @api.depends('odoo_product_id')
    def _compute_has_variants(self):
        for rec in self:
            if rec.odoo_product_id:
                tmpl = rec.odoo_product_id.product_tmpl_id
                variants = tmpl.product_variant_ids
                rec.product_template_id = tmpl.id
                rec.has_variants = len(variants) > 1
                rec.variant_count = len(variants)
            else:
                rec.product_template_id = False
                rec.has_variants = False
                rec.variant_count = 0

    # --- Onchange / Defaults ---

    @api.onchange('odoo_product_id')
    def _onchange_odoo_product(self):
        if self.odoo_product_id:
            product = self.odoo_product_id
            self.product_name = product.name.upper() if product.name else ''
            self.wc_product_name = product.name.title() if product.name else ''
            self.sale_price = product.list_price
            self.cost_price = product.standard_price
            self.sku = product.default_code or ''
            self.odoo_category_id = product.categ_id.id if product.categ_id else False
            # Auto-set sales tax
            if product.taxes_id:
                self.sales_tax_id = product.taxes_id[0].id
            # Auto-set image
            if product.image_1920:
                self.image_1 = product.image_1920

            # Populate variant lines
            tmpl = product.product_tmpl_id
            variants = tmpl.product_variant_ids
            if len(variants) > 1:
                lines = []
                for variant in variants:
                    attr_values = ', '.join(
                        variant.product_template_attribute_value_ids.mapped('name')
                    )
                    lines.append((0, 0, {
                        'product_id': variant.id,
                        'variant_name': variant.display_name,
                        'attribute_values': attr_values,
                        'sku': variant.default_code or '',
                        'sale_price': variant.list_price,
                        'cost_price': variant.standard_price,
                        'image': variant.image_variant_1920 or False,
                        'include': True,
                    }))
                self.variant_line_ids = lines
            else:
                self.variant_line_ids = [(5, 0, 0)]

    @api.onchange('odoo_category_id')
    def _onchange_category(self):
        """Auto-map Odoo category to WC category using woo.category.map."""
        if self.odoo_category_id and self.instance_id:
            mapping = self.env['woo.category.map'].search([
                ('instance_id', '=', self.instance_id.id),
                ('odoo_category_id', '=', self.odoo_category_id.id),
            ], limit=1)
            if mapping:
                self.wc_category_id = mapping.woo_category_id
                self.wc_category_name = mapping.woo_category_name

    @api.onchange('sales_tax_id')
    def _onchange_sales_tax(self):
        """Auto-map sales tax to WC tax class and match purchase tax."""
        if self.sales_tax_id and self.instance_id:
            # Map to WC tax class
            tax_map = self.env['woo.tax.map'].search([
                ('instance_id', '=', self.instance_id.id),
                ('tax_id', '=', self.sales_tax_id.id),
            ], limit=1)
            if tax_map:
                self.wc_tax_class = tax_map.woo_tax_class

            # Match purchase tax by amount
            purchase_tax = self.env['account.tax'].search([
                ('type_tax_use', '=', 'purchase'),
                ('amount', '=', self.sales_tax_id.amount),
                ('company_id', '=', self.instance_id.company_id.id),
            ], limit=1)
            if purchase_tax:
                self.purchase_tax_id = purchase_tax.id

    # --- Navigation ---

    def action_next(self):
        self.ensure_one()
        steps = ['basic', 'images', 'content', 'review']
        idx = steps.index(self.step)
        if idx < len(steps) - 1:
            self.step = steps[idx + 1]
        return self._reopen()

    def action_back(self):
        self.ensure_one()
        steps = ['basic', 'images', 'content', 'review']
        idx = steps.index(self.step)
        if idx > 0:
            self.step = steps[idx - 1]
        return self._reopen()

    def _reopen(self):
        return {
            'type': 'ir.actions.act_window',
            'res_model': self._name,
            'res_id': self.id,
            'views': [(False, 'form')],
            'target': 'new',
        }

    # --- AI Methods ---

    def _get_ai_service(self):
        """Get AIService instance from the woo.instance settings."""
        self.ensure_one()
        inst = self.instance_id
        if not inst.ai_provider or not inst.ai_api_key:
            raise UserError(
                "Please configure AI settings (Provider + API Key) on the WooCommerce instance first."
            )
        return AIService(inst.ai_provider, inst.ai_api_key, inst.ai_model or None)

    def action_ai_generate_all(self):
        """Generate all content fields using AI."""
        self.ensure_one()
        ai = self._get_ai_service()
        inst = self.instance_id

        product_info = {
            'name': self.product_name or '',
            'category': self.odoo_category_id.complete_name if self.odoo_category_id else '',
            'price': self.sale_price,
            'sku': self.sku or '',
            'raw_description': self.raw_product_info or '',
            'keywords': self.ai_keywords or '',
        }
        prompts = {
            'title': inst.prompt_product_title or '',
            'short_desc': inst.prompt_short_description or '',
            'long_desc': inst.prompt_long_description or '',
            'meta_title': inst.prompt_meta_title or '',
            'meta_desc': inst.prompt_meta_description or '',
            'keywords': inst.prompt_keywords or '',
        }

        result = ai.generate_product_content(product_info, prompts)

        self.wc_title = result.get('title', self.wc_product_name)
        self.short_description = result.get('short_description', '')
        self.long_description = result.get('long_description', '')
        self.meta_title = result.get('meta_title', '')
        self.meta_description = result.get('meta_description', '')
        self.seo_keywords = result.get('keywords', self.ai_keywords or '')

        return self._reopen()

    def action_ai_generate_title(self):
        self.ensure_one()
        ai = self._get_ai_service()
        product_info = {
            'name': self.product_name,
            'category': self.odoo_category_id.complete_name if self.odoo_category_id else '',
            'raw_description': self.raw_product_info or '',
        }
        result = ai.generate_single_field(
            product_info,
            self.instance_id.prompt_product_title or 'Generate SEO product title in Title Case',
            'title',
        )
        self.wc_title = result
        return self._reopen()

    def action_ai_generate_short_desc(self):
        self.ensure_one()
        ai = self._get_ai_service()
        product_info = {
            'name': self.product_name,
            'category': self.odoo_category_id.complete_name if self.odoo_category_id else '',
            'raw_description': self.raw_product_info or '',
        }
        result = ai.generate_single_field(
            product_info,
            self.instance_id.prompt_short_description or 'Write a short HTML product description',
            'short_description',
        )
        self.short_description = result
        return self._reopen()

    def action_ai_generate_long_desc(self):
        self.ensure_one()
        ai = self._get_ai_service()
        product_info = {
            'name': self.product_name,
            'category': self.odoo_category_id.complete_name if self.odoo_category_id else '',
            'raw_description': self.raw_product_info or '',
            'keywords': self.ai_keywords or '',
        }
        result = ai.generate_single_field(
            product_info,
            self.instance_id.prompt_long_description or 'Write a detailed HTML product description',
            'long_description',
        )
        self.long_description = result
        return self._reopen()

    def action_ai_generate_meta(self):
        self.ensure_one()
        ai = self._get_ai_service()
        product_info = {
            'name': self.wc_title or self.product_name,
            'category': self.odoo_category_id.complete_name if self.odoo_category_id else '',
            'keywords': self.ai_keywords or '',
        }
        self.meta_title = ai.generate_single_field(
            product_info,
            self.instance_id.prompt_meta_title or 'Generate SEO meta title under 60 chars',
            'meta_title',
        )
        self.meta_description = ai.generate_single_field(
            product_info,
            self.instance_id.prompt_meta_description or 'Generate SEO meta description under 160 chars',
            'meta_description',
        )
        return self._reopen()

    def action_ai_generate_keywords(self):
        self.ensure_one()
        ai = self._get_ai_service()
        product_info = {
            'name': self.wc_title or self.product_name,
            'category': self.odoo_category_id.complete_name if self.odoo_category_id else '',
            'raw_description': self.raw_product_info or '',
        }
        self.seo_keywords = ai.generate_single_field(
            product_info,
            self.instance_id.prompt_keywords or 'Generate SEO focus keywords',
            'keywords',
        )
        return self._reopen()

    # --- Image AI ---

    def action_ai_tag_images(self):
        """Generate AI metadata for all uploaded images."""
        self.ensure_one()
        ai = self._get_ai_service()
        inst = self.instance_id
        category_name = self.odoo_category_id.complete_name if self.odoo_category_id else ''

        metadata = []
        for i in range(1, 6):
            img = getattr(self, f'image_{i}', None)
            if img:
                meta = ai.generate_image_metadata(
                    self.product_name or '',
                    category_name,
                    inst.prompt_image_alt or 'Descriptive alt text under 125 chars',
                    inst.prompt_image_caption or 'Short product image caption',
                )
                meta['index'] = i
                metadata.append(meta)

        self.image_metadata = json.dumps(metadata)
        return self._reopen()

    def action_geo_tag_images(self):
        """Write EXIF geo-tag data to all uploaded images."""
        self.ensure_one()
        inst = self.instance_id
        for i in range(1, 6):
            img = getattr(self, f'image_{i}', None)
            if img:
                tagged = ImageProcessor.geo_tag_image(
                    img.decode('utf-8') if isinstance(img, bytes) else img,
                    inst.geo_company_name,
                    inst.geo_company_address,
                    inst.geo_company_phone,
                    inst.geo_lat,
                    inst.geo_lng,
                )
                setattr(self, f'image_{i}', tagged)

        self.images_geotagged = True
        return self._reopen()

    # --- Create Product ---

    def action_create_product(self):
        """Create the product in WooCommerce and update Odoo."""
        self.ensure_one()
        inst = self.instance_id
        client = inst._get_client()

        # --- Update/Create Odoo product ---
        odoo_product = self.odoo_product_id
        odoo_vals = {
            'name': self.product_name or (self.wc_title or '').upper(),
            'list_price': self.sale_price,
            'standard_price': self.cost_price,
            'default_code': self.sku or '',
            'type': 'consu',
        }
        if self.odoo_category_id:
            odoo_vals['categ_id'] = self.odoo_category_id.id
        if self.sales_tax_id:
            odoo_vals['taxes_id'] = [(6, 0, [self.sales_tax_id.id])]
        if self.purchase_tax_id:
            odoo_vals['supplier_taxes_id'] = [(6, 0, [self.purchase_tax_id.id])]

        if odoo_product:
            odoo_product.write(odoo_vals)
        else:
            odoo_product = self.env['product.product'].create(odoo_vals)

        # Set product image
        if self.image_1:
            odoo_product.image_1920 = self.image_1

        # --- Prepare WC product data ---
        wc_data = {
            'name': self.wc_title or (self.product_name or '').title(),
            'type': 'simple',
            'regular_price': str(self.sale_price),
            'sku': self.sku or '',
            'short_description': self.short_description or '',
            'description': self.long_description or '',
            'manage_stock': False,
            'status': 'publish',
        }

        # Category
        if self.wc_category_id:
            wc_data['categories'] = [{'id': self.wc_category_id}]

        # Tax class
        if self.wc_tax_class:
            wc_data['tax_class'] = self.wc_tax_class

        # SEO meta data — compatible with Rank Math, Yoast, AIOSEO, SEOPress
        seo_meta = []
        if self.meta_title:
            seo_meta.extend([
                {'key': 'rank_math_title', 'value': self.meta_title},
                {'key': '_yoast_wpseo_title', 'value': self.meta_title},
                {'key': '_aioseo_title', 'value': self.meta_title},
                {'key': '_seopress_titles_title', 'value': self.meta_title},
            ])
        if self.meta_description:
            seo_meta.extend([
                {'key': 'rank_math_description', 'value': self.meta_description},
                {'key': '_yoast_wpseo_metadesc', 'value': self.meta_description},
                {'key': '_aioseo_description', 'value': self.meta_description},
                {'key': '_seopress_titles_desc', 'value': self.meta_description},
            ])
        if self.seo_keywords:
            seo_meta.extend([
                {'key': 'rank_math_focus_keyword', 'value': self.seo_keywords},
                {'key': '_yoast_wpseo_focuskw', 'value': self.seo_keywords},
                {'key': '_aioseo_keywords', 'value': self.seo_keywords},
                {'key': '_seopress_analysis_target_kw', 'value': self.seo_keywords},
            ])
        if seo_meta:
            wc_data['meta_data'] = seo_meta

        # --- Upload images to WC ---
        image_metadata = []
        try:
            image_metadata = json.loads(self.image_metadata or '[]')
        except (json.JSONDecodeError, TypeError):
            pass

        wc_images = []
        for i in range(1, 6):
            img_data = getattr(self, f'image_{i}', None)
            if not img_data:
                continue
            filename = getattr(self, f'image_{i}_filename', '') or f'product_image_{i}.jpg'

            # Find AI metadata for this image
            img_meta = next((m for m in image_metadata if m.get('index') == i), {})

            # Upload image via WordPress REST API
            try:
                img_bytes = base64.b64decode(
                    img_data if isinstance(img_data, str) else img_data.decode('utf-8')
                )

                import requests
                wp_url = inst.url.rstrip('/')
                upload_url = f"{wp_url}/wp-json/wp/v2/media"

                headers = {
                    'Content-Disposition': f'attachment; filename="{filename}"',
                    'Content-Type': 'image/jpeg',
                }

                resp = requests.post(
                    upload_url,
                    auth=(inst.consumer_key, inst.consumer_secret),
                    headers=headers,
                    data=img_bytes,
                    timeout=60,
                )

                if resp.status_code in (200, 201):
                    media = resp.json()
                    wc_img = {
                        'id': media['id'],
                        'alt': img_meta.get('alt_text', ''),
                        'name': img_meta.get('title', filename),
                        'caption': img_meta.get('caption', ''),
                        'description': img_meta.get('description', ''),
                    }
                    # First image is featured
                    if i == 1:
                        wc_img['position'] = 0
                    wc_images.append(wc_img)
                else:
                    _logger.warning(
                        "Image upload failed (HTTP %s): %s",
                        resp.status_code, resp.text[:200],
                    )
            except Exception as e:
                _logger.error("Image upload error: %s", str(e))

        if wc_images:
            wc_data['images'] = wc_images

        # --- Handle variable vs simple product ---
        if self.has_variants:
            tmpl = self.product_template_id

            # Build WC attributes from Odoo attribute lines
            wc_attributes = []
            for attr_line in tmpl.attribute_line_ids:
                attr_name = attr_line.attribute_id.name
                attr_values = attr_line.value_ids.mapped('name')

                # Find or create WC attribute
                wc_attr = self._find_or_create_wc_attribute(client, attr_name)

                # Create terms for each value
                wc_terms = []
                for val_name in attr_values:
                    term = self._find_or_create_wc_attribute_term(client, wc_attr['id'], val_name)
                    wc_terms.append(term['name'])

                wc_attributes.append({
                    'id': wc_attr['id'],
                    'name': attr_name,
                    'position': 0,
                    'visible': True,
                    'variation': True,
                    'options': wc_terms,
                })

            wc_data['type'] = 'variable'
            wc_data['attributes'] = wc_attributes
            # Remove regular_price for variable products (set on variations)
            wc_data.pop('regular_price', None)

            # Create the parent product
            try:
                wc_product = client.create_product(wc_data)
                wc_product_id = wc_product['id']
                wc_permalink = wc_product.get('permalink', '')
            except Exception as e:
                raise UserError("Failed to create WooCommerce variable product: %s" % str(e))

            # Create parent product map
            self.env['woo.product.map'].create({
                'instance_id': inst.id,
                'product_id': odoo_product.id,
                'woo_product_id': wc_product_id,
                'woo_product_name': wc_data['name'],
                'woo_sku': self.sku or '',
                'woo_regular_price': 0,
                'woo_sale_price': 0,
                'woo_permalink': wc_permalink,
                'woo_product_type': 'variable',
                'state': 'mapped',
                'company_id': inst.company_id.id,
            })

            # Create variations
            variation_count = 0
            for line in self.variant_line_ids:
                if not line.include:
                    continue

                variant = line.product_id
                # Build variation attributes
                var_attributes = []
                for ptav in variant.product_template_attribute_value_ids:
                    var_attributes.append({
                        'name': ptav.attribute_id.name,
                        'option': ptav.name,
                    })

                var_data = {
                    'regular_price': str(line.sale_price),
                    'sku': line.sku or '',
                    'attributes': var_attributes,
                    'manage_stock': True,
                    'stock_quantity': int(variant.qty_available),
                }

                # Upload variant image if present
                if line.image:
                    try:
                        img_bytes = base64.b64decode(
                            line.image if isinstance(line.image, str) else line.image.decode('utf-8')
                        )
                        import requests as req
                        wp_url = inst.url.rstrip('/')
                        upload_url = f"{wp_url}/wp-json/wp/v2/media"
                        var_filename = f"variant_{line.sku or variant.id}.jpg"
                        headers = {
                            'Content-Disposition': f'attachment; filename="{var_filename}"',
                            'Content-Type': 'image/jpeg',
                        }
                        resp = req.post(
                            upload_url,
                            auth=(inst.consumer_key, inst.consumer_secret),
                            headers=headers,
                            data=img_bytes,
                            timeout=60,
                        )
                        if resp.status_code in (200, 201):
                            media = resp.json()
                            var_data['image'] = {'id': media['id']}
                    except Exception as img_e:
                        _logger.warning("Variant image upload failed for %s: %s", line.variant_name, img_e)

                # Tax class
                if self.wc_tax_class:
                    var_data['tax_class'] = self.wc_tax_class

                try:
                    wc_variation = client.create_product_variation(wc_product_id, var_data)

                    # Create variation product map
                    self.env['woo.product.map'].create({
                        'instance_id': inst.id,
                        'product_id': variant.id,
                        'woo_product_id': wc_variation['id'],
                        'woo_product_name': line.variant_name,
                        'woo_sku': line.sku or '',
                        'woo_regular_price': line.sale_price,
                        'woo_sale_price': 0,
                        'woo_permalink': wc_permalink,
                        'woo_product_type': 'simple',
                        'woo_parent_id': wc_product_id,
                        'is_variation': True,
                        'state': 'mapped',
                        'company_id': inst.company_id.id,
                    })
                    variation_count += 1
                except Exception as e:
                    _logger.error("Failed to create variation for %s: %s", line.variant_name, e)

            inst._log_sync(
                'product', 'odoo_to_woo', tmpl.name, 'success',
                'Created variable product with %d variations' % variation_count,
            )

            success_msg = 'Variable product "%s" created with %d variations!' % (wc_data['name'], variation_count)
        else:
            # --- Simple product creation ---
            try:
                wc_product = client.create_product(wc_data)
                wc_product_id = wc_product['id']
                wc_permalink = wc_product.get('permalink', '')
            except Exception as e:
                raise UserError("Failed to create WooCommerce product: %s" % str(e))

            # Create product mapping
            self.env['woo.product.map'].create({
                'instance_id': inst.id,
                'product_id': odoo_product.id,
                'woo_product_id': wc_product_id,
                'woo_product_name': wc_data['name'],
                'woo_sku': self.sku or '',
                'woo_regular_price': self.sale_price,
                'woo_sale_price': 0.0,
                'woo_permalink': wc_permalink,
                'woo_product_type': 'simple',
                'state': 'mapped',
                'company_id': inst.company_id.id,
            })

            inst._log_sync(
                'product', 'odoo_to_woo', odoo_product.name, 'success',
                'Created WC product #%s' % wc_product_id,
            )

            success_msg = 'Product "%s" created in WooCommerce successfully!' % wc_data['name']

        # Close wizard and show success
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': 'Product Created',
                'message': success_msg,
                'type': 'success',
                'sticky': False,
                'next': {'type': 'ir.actions.act_window_close'},
            },
        }

    # --- Variant Helper Methods ---

    def _find_or_create_wc_attribute(self, client, attr_name):
        """Find or create a WC product attribute by name."""
        try:
            attrs = client.get_product_attributes()
            for a in attrs:
                if a.get('name', '').lower() == attr_name.lower():
                    return a
        except Exception:
            pass
        # Create new attribute
        return client.create_product_attribute({
            'name': attr_name,
            'slug': attr_name.lower().replace(' ', '-'),
            'type': 'select',
            'order_by': 'menu_order',
        })

    def _find_or_create_wc_attribute_term(self, client, attr_id, term_name):
        """Find or create a WC attribute term."""
        try:
            terms = client.get_attribute_terms(attr_id)
            for t in terms:
                if t.get('name', '').lower() == term_name.lower():
                    return t
        except Exception:
            pass
        # Create new term
        return client.create_attribute_term(attr_id, {
            'name': term_name,
        })
