# Copyright © 2025 Nexa Systems Inc (https://nexasystems.ca)
# @author: Nexa Systems Inc (support@nexasystems.ca)

# License OPL-1 (https://www.odoo.com/documentation/19.0/legal/licenses.html).

import base64
from typing import List

from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.addons.base.models.res_partner import _lang_get
class PrintProductLabel(models.TransientModel):
    _name = "print.product.label"
    _description = 'Wizard to print Product Labels'

    @api.model
    def _complete_label_fields(self, label_ids: List[int]) -> List[int]:
        """Set additional fields for product labels. Method to override."""
        # Increase a label sequence
        labels = self.env['print.product.label.line'].browse(label_ids)
        for seq, label in enumerate(labels):
            label.sequence = 1000 + seq
        return label_ids

    @api.model
    def _get_product_label_ids(self):
        res = []
        # flake8: noqa: E501
        if self._context.get('active_model') == 'product.template':
            products = self.env[self._context.get('active_model')].browse(
                self._context.get('default_product_template_ids')
            )
            for product in products:
                label = self.env['print.product.label.line'].create({
                    'product_id': product.product_variant_id.id,
                })
                res.append(label.id)
        elif self._context.get('active_model') == 'product.product':
            products = self.env[self._context.get('active_model')].browse(
                self._context.get('default_product_product_ids')
            )
            for product in products:
                label = self.env['print.product.label.line'].create({'product_id': product.id})
                res.append(label.id)
        res = self._complete_label_fields(res)
        return res

    @api.model
    def default_get(self, fields_list):
        default_vals = super(PrintProductLabel, self).default_get(fields_list)
        if 'label_type_id' in fields_list and not default_vals.get('label_type_id'):
            default_vals['label_type_id'] = self.env.ref('fusion_labels.type_product').id
        return default_vals

    name = fields.Char(default='Print Product Labels')
    message = fields.Char(readonly=True)
    output = fields.Selection(selection=[('pdf', 'PDF')], string='Print to', default='pdf')
    mode = fields.Selection(
        selection=[('product.product', 'Products')],
        help='Technical field to specify the mode of the label printing wizard.',
        default='product.product',
    )
    label_type_id = fields.Many2one(comodel_name='print.label.type', string='Label Type')
    label_ids = fields.One2many(
        comodel_name='print.product.label.line',
        inverse_name='wizard_id',
        string='Labels for Products',
        default=_get_product_label_ids,
    )
    report_id = fields.Many2one(
        comodel_name='ir.actions.report',
        string='Label',
        domain=[('model', '=', 'print.product.label.line')],
    )
    is_template_report = fields.Boolean(compute='_compute_is_template_report')
    qty_per_product = fields.Integer(
        string='Label quantity per product',
        default=1,
    )
    # Options
    humanreadable = fields.Boolean(
        string='Human readable barcode',
        help='Print digital code of barcode.',
        default=False,
    )
    border_width = fields.Integer(
        string='Border',
        help='Border width for labels (in pixels). Set "0" for no border.'
    )
    lang = fields.Selection(
        selection=_lang_get,
        string='Language',
        help="The language that will be used to translate label names.",
    )
    company_id = fields.Many2one(
        comodel_name='res.company',
        help='Specify a company for product labels.'
    )

    @api.depends('report_id')
    def _compute_is_template_report(self):
        for wizard in self:
            # flake8: noqa: E501
            wizard.is_template_report = self.report_id == self.env.ref('fusion_labels.action_report_product_label_from_template')

    def get_labels_to_print(self):
        self.ensure_one()
        labels = self.label_ids.filtered(lambda l: l.selected and l.qty)
        if not labels:
            raise UserError(_('Nothing to print, set the quantity of labels in the table.'))
        return labels

    def _get_report_action_params(self):
        """Return two params for a report action: record "ids" and "data"."""
        self.ensure_one()
        return self.get_labels_to_print().ids, None

    def _prepare_report(self):
        self.ensure_one()
        output_mode = self._context.get('print_mode', 'pdf')
        if not self.report_id:
            raise UserError(_('Please select a label type.'))
        report = self.report_id.with_context(discard_logo_check=True, lang=self.lang)
        report.sudo().write({'report_type': f'qweb-{output_mode}'})
        return report

    def action_print(self):
        """Print labels."""
        self.ensure_one()
        report = self._prepare_report()
        return report.report_action(*self._get_report_action_params())

    def action_set_qty(self):
        """Set a specific number of labels for all lines."""
        self.ensure_one()
        self.label_ids.write({'qty': self.qty_per_product})

    def action_restore_initial_qty(self):
        """Restore the initial number of labels for all lines."""
        self.ensure_one()
        for label in self.label_ids:
            if label.qty_initial:
                label.update({'qty': label.qty_initial})

    @api.model
    def get_quick_report_action(
            self, model_name: str, ids: List[int], qty: int = None, template=None, force_direct: bool = False,
    ):
        """ Allow to get a report action for custom labels. Method to override. """
        wizard = self.with_context(
            **{'active_model': model_name, f'default_{model_name.replace(".", "_")}_ids': ids}
        ).create({'report_id': self.env.ref('fusion_labels.action_report_product_label_50x38').id})
        return wizard.action_print()

    @api.model
    def _set_sequence(self, lbl, seq, processed):
        if lbl in processed:
            return seq, processed
        lbl.sequence = seq
        seq += 1
        processed += lbl
        return seq, processed

    def action_sort_by_product(self):
        self.ensure_one()
        sequence = 1000
        processed_labels = self.env['print.product.label.line'].browse()
        # flake8: noqa: E501
        for label in self.label_ids:
            sequence, processed_labels = self._set_sequence(label, sequence, processed_labels)
            tmpl_labels = self.label_ids.filtered(lambda l: l.product_id.product_tmpl_id == label.product_id.product_tmpl_id).sorted(lambda l: l.product_id.id, reverse=True) - label
            for tmpl_label in tmpl_labels:
                sequence, processed_labels = self._set_sequence(tmpl_label, sequence, processed_labels)
                product_labels = tmpl_labels.filtered(lambda l: l.product_id == label.product_id) - tmpl_label
                for product_label in product_labels:
                    sequence, processed_labels = self._set_sequence(product_label, sequence, processed_labels)

    def get_pdf(self):
        self.ensure_one()
        report = self.with_context(print_mode='pdf')._prepare_report()
        pdf_data = report._render_qweb_pdf(report, *self._get_report_action_params())
        return base64.b64encode(pdf_data[0])
