# translation
from django.utils.translation import gettext_lazy as _
from django.core.validators import MinValueValidator
from django.core.validators import MaxValueValidator

# printer support
import socket
import json

# barcode helpers
from InvenTree.helpers_model import getModelsWithMixin
from InvenTree.models import InvenTreeBarcodeMixin

# InvenTree plugin libs
from plugin import InvenTreePlugin
from plugin.mixins import LabelPrintingMixin, SettingsMixin, BarcodeMixin

from inventree_phomemo.version import PHOMEMO_PLUGIN_VERSION

class PhomemoLabelPlugin(LabelPrintingMixin, BarcodeMixin, SettingsMixin, InvenTreePlugin):
    AUTHOR = "Sergal.engineering"
    DESCRIPTION = "Label printing plugin for Phomemo printers"
    VERSION = PHOMEMO_PLUGIN_VERSION
    NAME = "Phomemo"
    SLUG = "phomemo"
    TITLE = "Phomemo Label Printer"

    SETTINGS = {
        'IP_ADDRESS': {
            'name': _('IP Address'),
            'description': _('IP address of phomemo print server'),
            'default': '',
        },
        'PORT': {
            'name': _('Port'),
            'description': _('Port of phomemo print server'),
            'default': '9100',
        },
    }

    def print_label(self, **kwargs):

        # Read settings
        ip_address = self.get_setting('IP_ADDRESS')
        port = int(self.get_setting('PORT'))
        
        object_to_print = kwargs['label_instance'].object_to_print

        match kwargs['label_instance'].SUBDIR:
            case 'part':
                tpart = object_to_print
                barcode = '1' + str(object_to_print.pk)
            case 'stockitem':
                tpart = object_to_print.part
                barcode = '2' + str(object_to_print.pk)
            case 'stocklocation':
                tpart = object_to_print
                barcode = '3' + str(object_to_print.pk)
            case 'build':
                tpart = object_to_print
                barcode = '4' + str(object_to_print.pk)
            case _:
                tpart = object_to_print
                barcode = '0' + str(object_to_print.pk)
                print(f"!! Unsupported item type: {kwargs['label_instance'].SUBDIR}")
        
        fields = {
            'name': tpart.name,
            'description': tpart.description,
            'pk': tpart.pk,
            'params': tpart.parameters_map() if hasattr(tpart, 'parameters_map') else None,
            'category': tpart.category.name if hasattr(tpart, 'category') else None,
            'category_path': tpart.category.pathstring if hasattr(tpart, 'category') else None,
            'barcode': barcode,
            'type': kwargs['label_instance'].SUBDIR
        }

        data = json.dumps(fields)

        # Send the label to the printer
        try:
            print_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            print_socket.settimeout(5)
            print_socket.connect((ip_address, port))
            print_socket.sendall(bytes(data,encoding="utf-8"))
            print_socket.close()
        except Exception as error:
            raise ConnectionError('Error connecting to printer server: ' + str(error))
    

    @staticmethod
    def get_supported_barcode_models():
        """Returns a list of database models which support barcode functionality."""
        return getModelsWithMixin(InvenTreeBarcodeMixin)

    def format_matched_response(self, label, model, instance):
        """Format a response for the scanned data."""
        return {label: instance.format_matched_response()}
    
    def scan(self, barcode_data):
        # Our barcode should be a string
        if type(barcode_data) is not str:
            barcode_data = str(barcode_data)
        
        # Our barcodes are at least two symbols long
        if len(barcode_data) < 2:
            return
        
        match barcode_data[0]:
            case '1':
                model_type = 'part'
            case '2':
                model_type = 'stockitem'
            case '3':
                model_type = 'stocklocation'
            case '4':
                model_type = 'build'

        supported_models = self.get_supported_barcode_models()

        for model in supported_models:
            label = model.barcode_model_type()

            if label == model_type:
                try:
                    pk = int(barcode_data[1:])
                    instance = model.objects.get(pk=pk)
                    return self.format_matched_response(label, model, instance)
                except (ValueError, model.DoesNotExist):
                    pass