# -*- coding: utf-8 -*-
import os
import os.path
import sqlite3
from munch import munchify

from openprocurement.search.source import BaseSource

from logging import getLogger
logger = getLogger(__name__)


class OrgsDecoder(object):
    def __init__(self, config={}):
        self.db_conn = None
        self.db_curs = None
        self.q_cache = {}
        orgs_db_size = 0
        if config.get('orgs_db'):
            orgs_db_size = os.path.getsize(config['orgs_db'])
        if orgs_db_size < 10000: # don't accept empty database
            logger.warning("%s not exists or empty", config['orgs_db'])
            return
        try:
            fd = os.open(config['orgs_db'], os.O_RDONLY)
            self.db_conn = sqlite3.connect('/dev/fd/%d' % fd)
            os.close(fd)
        except Exception as e:
            logger.warning("Can't open %s via os.open(/dev/fd) %s",
                config['orgs_db'], str(e))
            self.db_conn = sqlite3.connect(config['orgs_db'])
        self.db_curs = self.db_conn.cursor()

    def is_connected(self):
        return self.db_curs

    def __del__(self):
        self.close()

    def close(self):
        try:
            if self.db_conn:
                self.db_conn.close()
        except Exception as e:
            logger.error("OrgsDecoder.close %s", str(e))
        self.db_curs = None
        self.db_conn = None

    def query(self, code):
        if not self.db_curs or not code:
            return
        if type(code) != str:
            try:
                code = str(code)
            except (TypeError, UnicodeEncodeError):
                return
        while len(code) < 8:
            code = "0" + code
        if code in self.q_cache:
            # get cached row and increase hits count
            row = self.q_cache[code][0]
            self.q_cache[code][1] += 1
            return row
        if len(self.q_cache) > 10000:
            for k, v in self.q_cache.items():
                if v[1] < 5:
                    self.q_cache.pop(k)
            logger.info("Purge orgs cache, new len %d", len(self.q_cache))
        try:
            self.db_curs.execute("SELECT code,name,short,loc FROM uo WHERE code=?", (code,))
            row = self.db_curs.fetchone()
            if row and len(row) > 2:
                row = (row[0], row[1], row[2], row[3])
                self.q_cache[code] = [row, 1]
                return row
        except Exception as e:
            logger.error("OrgsDecoder.query %s: %s", code, str(e))
            self.db_curs = None
        return

    def patch_entity(self, entity):
        if not self.db_curs or not entity:
            return
        try:
            if 'registryRecord' in entity:
                return
            if 'identifier' not in entity:
                return
            if entity['identifier'].get('scheme') != 'UA-EDR':
                return
            code = entity['identifier'].get('id')
            row = self.query(code)
            if not row:
                return
            entity['registryRecord'] = {
                'edrpou': row[0],
                'name': row[1],
                'shortName': row[2],
                'location': row[3]
            }
        except Exception as e:
            logger.error("OrgsDecoder.patch_entity %s: %s", entity, str(e))


class OrgsSource(BaseSource):
    """Organisations fake source
    """
    __doc_type__ = 'org'

    config = {
        'orgs_db': None,
        'orgs_queue': 1000,
    }

    def __init__(self, config={}):
        if config:
            self.config.update(config)
        self.orgs_db = None
        self.queue_size = int(self.config['orgs_queue'])
        self.queue = {}

    def patch_item(self, item):
        item_data = item.get('data', {})
        data = {
            "edrpou": item['id'],
            "location": item_data.get('address', {}).get('region', u""),
            "name": (item_data.get('name') or item_data.get('name_ru') or
                     item_data.get('identifier', {}).get('legalName', u"")),
            "short": u"",
            "rank": 1,
        }
        if self.orgs_db and item.get('id'):
            row = self.orgs_db.query(item['id'])
            if row:
                data['name'] = row[1]
                data['short'] = row[2]
                data['location'] = row[3]
        return {'meta': item, 'data': data}

    def reset(self):
        if self.orgs_db:
            self.orgs_db.close()
        if self.config['orgs_db']:
            orgs_db_size = os.path.getsize(self.config['orgs_db'])
            logger.info("Open UA-EDR database %s size %d MB",
                self.config['orgs_db'], orgs_db_size/1024000)
            self.orgs_db = OrgsDecoder(self.config)
        if not self.orgs_db or not self.orgs_db.db_conn:
            logger.warning("No UA-EDR database, orgs will not decoded")
            self.orgs_db = None
        self.queue = {}

    def push(self, item):
        """push item in to queue and return True if need to flush"""
        try:
            code = item['identifier']['id']
            if code and type(code) == int:
                code = str(code)
            if len(code) < 5 or len(code) > 15:
                raise ValueError("Bad code")
        except (KeyError, TypeError, ValueError):
            return False
        name = (item.get('name') or item.get('name_ru') or
                item.get('identifier', {}).get('legalName', u""))
        if not name or len(name) < 3:
            return False
        if code not in self.queue:
            data = {
                'id': code,
                'dateModified': "",
                'doc_type': self.doc_type,
                'version': 1L,
                'data': item,
            }
            self.queue[code] = munchify(data)
        if len(self.queue) >= self.queue_size:
            return True
        return False

    def items(self, name=None):
        for item in self.queue.values():
            yield item
        self.queue = {}

    def get(self, item):
        return self.patch_item(item)

@@ -3671,34 +3671,274 @@
        self.
-queue = %7B%7D
+should_reset = True%0A        self.queue = %7B%7D%0A%0A    def need_reset(self):%0A        if self.should_reset and len(self.queue) == 0:%0A            return True%0A        if not self.orgs_db and self.config%5B'orgs_db'%5D:%0A            return True%0A        return False
 %0A%0A    def pa
@@ -5121,32 +5121,66 @@
 .orgs_db = None%0A
+        self.should_reset = False%0A
         self.que

add OrgsSource.need_reset