import os

import json
import logging
import time

import base_detector
import paths


ID_SEPARATOR = "_"
RETRIES = 3

class PrinterID(dict):

    def __init__(self, vid, pid, snr, com=None, ip=None):
        self['VID'] = vid
        self['PID'] = pid
        self['SNR'] = snr
        if com:
            self['COM'] = com
        if ip:
            self['IP'] = ip

    def __eq__(self, other):
        if not isinstance(other, dict):
            raise TypeError
        for field_name in base_detector.BaseDetector.PRINTER_ID_DICT_KEYS:
            if self[field_name] != other[field_name]:
                return False
        return True


def create_id_string(usb_info: dict) -> str:
    try:
        id_string = ""
        for char in usb_info['VID'] + ID_SEPARATOR + \
                    usb_info['PID'] + ID_SEPARATOR + \
                    usb_info['SNR']:
            if char.isalnum():
                id_string += char
            else:
                id_string += ID_SEPARATOR
    except:
        id_string = "invalid_printer_id"
    return id_string


def load_settings(id_string, retries=RETRIES) -> dict:
    logger = logging.getLogger(id_string + ".settings")
    settings = {}
    settings_path = os.path.join(paths.PRINTER_SETTINGS_FOLDER, id_string + ".json")
    try:
        with open(settings_path) as f:
            settings = json.loads(f.read())
            logger.info('Settings loaded: ' + str(settings))
    except FileNotFoundError:
        pass
    except json.decoder.JSONDecodeError:
        logger.error(f'Unable to load printer settings for {id_string}')
        try:
            os.remove(settings_path)
            logger.error('Removing invalid settings file: {settings_path}')
        except OSError:
            pass
    except Exception as e:
        retries -= 1
        if retries:
            logger.error('Error loading settings:' + str(e))
            time.sleep(0.1)
            return load_settings(id_string, retries)
    return settings

def load_all_printer_settings() -> dict:
    all_printers = {}
    for filename in os.listdir(paths.PRINTER_SETTINGS_FOLDER):
        printer_id = filename.replace('.json', '')
        all_printers[printer_id] = load_settings(printer_id)
    return all_printers

def save_settings(id_string, settings, retries=RETRIES) -> bool:
    logger = logging.getLogger(id_string + ".settings")
    try:
        path = os.path.join(paths.PRINTER_SETTINGS_FOLDER, id_string + ".json")
        paths.check_and_create_dirs(path)
        with open(path, "w") as f:
            f.write(json.dumps(settings))
            logger.info('Settings saved: ' + str(settings))
            return True
    except OSError as e:
        retries -= 1
        if retries:
            time.sleep(0.05)
            return save_settings(id_string, settings, retries)
        logger.info(f'Error saving settings: {settings}\n{e}')
        return False


def reset_printer_settings(id_string):
    return save_settings(id_string, {})
