import logging 
import ipaddress

import config
import findssh

try:
    import ifaddr
except:
    ifaddr = None


class Scanner:

    PASS_CACHE_ATTR_NAME = None
    CAN_DETECT_SNR = False
    CAN_DETECT_VID_PID = False
    PORT = 0
    DEFAULT_PROFILE_ALIAS = ''
    DEFAULT_CONN_ID = None
    SCANNER_NAME_IN_PROFILE = []

    @staticmethod
    def get_network_interfaces():
        adapters = []
        if ifaddr:
            for i in ifaddr.get_adapters():
                for net_and_ip in i.ips: 
                    adapter = {}
                    adapter['name'] = i.nice_name 
                    prefix = getattr(net_and_ip, 'network_prefix', None)
                    ip = getattr(net_and_ip, 'ip', None)
                    if prefix and ip:
                        adapter['prefix'] = prefix
                        adapter['ip'] = ip
                        if isinstance(ip, tuple):
                            ip = ip[0]
                        try:
                            ip_obj = ipaddress.ip_address(ip)
                            if ip_obj.is_private and not ip_obj.is_loopback:
                                adapters.append(adapter)
                        except:
                            pass
        else:
            adapters.append({'name': 'no_ifaddr', 'ip': findssh.getLANip(), 'prefix': 24})
        return adapters

    def __init__(self, parent=None, profile=None, conn_id=None):
        self.logger = logging.getLogger(self.__class__.__name__)
        self.parent = parent
        self.using_default_profile = False
        if profile:
            self.profile = profile
            self.conn_id = conn_id
        else:
            if self.DEFAULT_PROFILE_ALIAS:
                self.using_default_profile = True
                self.profile = self.get_default_profile(self.DEFAULT_PROFILE_ALIAS)
            else:
                self.profile = None
        self.cached_http_hosts = []
        self.discovered_printers = []
        self.port = self.PORT
        self.interfaces = self.get_network_interfaces()
        self.logger.debug('Found net interfaces: ' + str(self.interfaces))
        self.profiles = self.get_scanner_compatible_profiles()
        self.vids_pids = self.get_possible_vids_pids()
        self.guess_vid_pid = False

    def get_scanner_compatible_profiles(self):
        profiles = []
        if self.profile: 
            profiles.append(self.profile)
        elif self.SCANNER_NAME_IN_PROFILE:
            for profile in config.get_profiles():
                if profile.get('network_detect', {}).get('scanner') in self.SCANNER_NAME_IN_PROFILE:
                    if profile not in profiles:
                        profiles.append(profile)
                else:
                    for conn in profile.get('v2', {}).get('connections', []):
                        if conn.get('scanner') in self.SCANNER_NAME_IN_PROFILE:
                            if profile not in profiles:
                                profiles.append(profile)
                                break
        return profiles

    def get_possible_vids_pids(self):
        if not self.profile:
            return []
        if self.conn_id:
            for conn in self.profile.get('v2', {}).get('connections', []):
                if conn.get('id') == self.conn_id:
                    vids_pids = []
                    for conn_vid_pid in conn.get('ids'):
                        vids_pids.append([conn_vid_pid['VID'], conn_vid_pid['PID']])
                    return vids_pids
            self.logger.warning(f'Unable to find a v2 connection for {self.conn_id} in ' + self.profile['alias'])
        else:
            return self.profile.get('vids_pids')

    def get_default_profile(self, profile_alias):
        if self.parent and getattr(self.parent, 'user_login', None):
            profiles = self.parent.user_login.profiles
        else:
            profiles = config.get_profiles()
        for profile in profiles:
            if profile['alias'] == profile_alias:
                return profile
        self.logger.warning('Unable to find a profile for ' + profile_alias)

    def get_discovered_printers(self):
        for printer in self.discovered_printers:
            if not 'VID' in printer or not 'PID' in printer:
                if self.vids_pids and self.guess_vid_pid:
                    printer['VID'], printer['PID'] = self.vids_pids[0]
                    if not 'SNR' in printer:
                        printer['SNR'] = printer['IP']
        return self.discovered_printers
