import logging
import secrets

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

from ..lib.woo_api_client import WooApiClient

_logger = logging.getLogger(__name__)


class WooInstance(models.Model):
    _name = 'woo.instance'
    _description = 'WooCommerce Instance'
    _inherit = ['mail.thread']

    name = fields.Char(required=True, tracking=True)
    url = fields.Char(required=True, tracking=True)
    consumer_key = fields.Char(groups='base.group_system')
    consumer_secret = fields.Char(groups='base.group_system')
    webhook_secret = fields.Char(groups='base.group_system')
    wc_api_version = fields.Char(default='wc/v3')
    odoo_api_key = fields.Char(groups='base.group_system')
    company_id = fields.Many2one(
        'res.company', required=True, default=lambda self: self.env.company,
    )
    sync_interval = fields.Selection(
        [('5', '5 Min'), ('15', '15 Min'), ('30', '30 Min'), ('60', '1 Hour')],
        default='15',
    )
    sync_products = fields.Boolean(default=True)
    sync_orders = fields.Boolean(default=True)
    sync_invoices = fields.Boolean(default=True)
    sync_inventory = fields.Boolean(default=True)
    sync_customers = fields.Boolean(default=True)
    default_warehouse_id = fields.Many2one('stock.warehouse')
    notify_on_failure = fields.Boolean()
    notify_user_ids = fields.Many2many('res.users')
    state = fields.Selection(
        [('draft', 'Draft'), ('connected', 'Connected'), ('error', 'Error')],
        default='draft', tracking=True,
    )
    last_sync = fields.Datetime(readonly=True)

    # Relational
    product_map_ids = fields.One2many('woo.product.map', 'instance_id')
    order_ids = fields.One2many('woo.order', 'instance_id')
    customer_ids = fields.One2many('woo.customer', 'instance_id')
    sync_log_ids = fields.One2many('woo.sync.log', 'instance_id')

    # Computed
    mapped_count = fields.Integer(compute='_compute_counts')
    unmapped_count = fields.Integer(compute='_compute_counts')
    error_count = fields.Integer(compute='_compute_counts')

    @api.depends('product_map_ids.state', 'sync_log_ids')
    def _compute_counts(self):
        for rec in self:
            rec.mapped_count = self.env['woo.product.map'].search_count([
                ('instance_id', '=', rec.id), ('state', '=', 'mapped'),
            ])
            rec.unmapped_count = self.env['woo.product.map'].search_count([
                ('instance_id', '=', rec.id), ('state', '=', 'unmapped'),
            ])
            yesterday = fields.Datetime.subtract(fields.Datetime.now(), hours=24)
            rec.error_count = self.env['woo.sync.log'].search_count([
                ('instance_id', '=', rec.id),
                ('state', '=', 'failed'),
                ('create_date', '>=', yesterday),
            ])

    def _get_client(self):
        """Return a WooApiClient instance for this WooCommerce connection."""
        self.ensure_one()
        if not self.consumer_key or not self.consumer_secret:
            raise UserError("Consumer key and secret are required.")
        return WooApiClient(
            url=self.url,
            consumer_key=self.consumer_key,
            consumer_secret=self.consumer_secret,
            api_version=self.wc_api_version or 'wc/v3',
        )

    def action_test_connection(self):
        """Test the WooCommerce connection and update state."""
        self.ensure_one()
        try:
            client = self._get_client()
            success, info = client.test_connection()
            if success:
                self.state = 'connected'
                self.message_post(body=f"Connection successful. WooCommerce version: {info}")
            else:
                self.state = 'error'
                self.message_post(body=f"Connection failed: {info}")
        except Exception as exc:
            self.state = 'error'
            self.message_post(body=f"Connection error: {exc}")
            _logger.exception("WooCommerce connection test failed for %s", self.name)

    def action_generate_api_key(self):
        """Generate a random API key for the Odoo webhook endpoint."""
        self.ensure_one()
        self.odoo_api_key = secrets.token_urlsafe(32)

    def _log_sync(self, sync_type, direction, record_ref, state, message=''):
        """Create a woo.sync.log record for this instance."""
        self.ensure_one()
        self.env['woo.sync.log'].sudo().create({
            'instance_id': self.id,
            'sync_type': sync_type,
            'direction': direction,
            'record_ref': record_ref,
            'state': state,
            'message': message,
            'company_id': self.company_id.id,
        })

    # ------------------------------------------------------------------
    # Cron entry points
    # ------------------------------------------------------------------

    @api.model
    def _cron_sync_products(self):
        """Sync product prices and inventory for all connected instances."""
        instances = self.search([('state', '=', 'connected'), ('sync_products', '=', True)])
        for instance in instances:
            try:
                instance._sync_products()
            except Exception as e:
                _logger.error("Product sync failed for %s: %s", instance.name, str(e))
                instance._log_sync('product', 'woo_to_odoo', instance.name, 'failed', str(e))
                instance._notify_failure('product', str(e))

    @api.model
    def _cron_sync_orders(self):
        """Fetch new orders from all connected WooCommerce instances."""
        instances = self.search([('state', '=', 'connected'), ('sync_orders', '=', True)])
        for instance in instances:
            try:
                instance._sync_orders()
            except Exception as e:
                _logger.error("Order sync failed for %s: %s", instance.name, str(e))
                instance._log_sync('order', 'woo_to_odoo', instance.name, 'failed', str(e))
                instance._notify_failure('order', str(e))

    @api.model
    def _cron_sync_inventory(self):
        """Push inventory levels to WooCommerce for all connected instances."""
        instances = self.search([('state', '=', 'connected'), ('sync_inventory', '=', True)])
        for instance in instances:
            try:
                instance._sync_inventory()
            except Exception as e:
                _logger.error("Inventory sync failed for %s: %s", instance.name, str(e))
                instance._log_sync('inventory', 'odoo_to_woo', instance.name, 'failed', str(e))
                instance._notify_failure('inventory', str(e))

    @api.model
    def _cron_sync_customers(self):
        """Sync customer address updates to WooCommerce."""
        instances = self.search([('state', '=', 'connected'), ('sync_customers', '=', True)])
        for instance in instances:
            try:
                instance._sync_customers()
            except Exception as e:
                _logger.error("Customer sync failed for %s: %s", instance.name, str(e))
                instance._log_sync('customer', 'odoo_to_woo', instance.name, 'failed', str(e))
                instance._notify_failure('customer', str(e))

    # ------------------------------------------------------------------
    # Sync method placeholders (filled in during later tasks)
    # ------------------------------------------------------------------

    def _sync_products(self):
        """Sync products — implemented in Task 22."""
        self.ensure_one()
        _logger.info("Product sync for %s — not yet implemented", self.name)

    def _sync_orders(self):
        """Sync orders — implemented in Task 20."""
        self.ensure_one()
        _logger.info("Order sync for %s — not yet implemented", self.name)

    def _sync_inventory(self):
        """Sync inventory — implemented in Task 22."""
        self.ensure_one()
        _logger.info("Inventory sync for %s — not yet implemented", self.name)

    def _sync_customers(self):
        """Sync customers — implemented in Task 25."""
        self.ensure_one()
        _logger.info("Customer sync for %s — not yet implemented", self.name)

    def _notify_failure(self, sync_type, error_message):
        """Send email notification on sync failure."""
        self.ensure_one()
        if not self.notify_on_failure or not self.notify_user_ids:
            return
        template = self.env.ref(
            'fusion_woocommerce.woo_sync_failure_notification', raise_if_not_found=False,
        )
        if template:
            for user in self.notify_user_ids:
                template.with_context(
                    sync_type=sync_type,
                    error_message=error_message,
                ).send_mail(self.id, force_send=True, email_values={'email_to': user.email})
