import json
import os
import uuid

from gi.repository import GObject
from xdg import BaseDirectory

import keyring

from rsr.connections.backends import get_available_drivers
from rsr.connections.connection import Connection


CONNECTIONS_FILE = os.path.join(BaseDirectory.save_config_path('runsqlrun'),
                                'connections.json')


class ConnectionManager(GObject.GObject):

    __gsignals__ = {
        'connection-deleted': (GObject.SIGNAL_RUN_LAST, None, (str,)),
    }

    def __init__(self, app):
        super(ConnectionManager, self).__init__()
        self.app = app
        self._connections = {}
        self.update_connections()

    def update_connections(self):
        if not os.path.exists(CONNECTIONS_FILE):
            return
        with open(CONNECTIONS_FILE) as f:
            data = json.load(f)
        for key in data:
            if key in self._connections:
                self._connections[key].update_config(data[key])
            else:
                config = data[key].copy()
                password = keyring.get_password('runsqlrun', key)
                if password is not None:
                    config['password'] = password
                conn = Connection(key, config)
                self._connections[key] = conn
                conn.start()
        # remove deleted connections
        for key in list(self._connections):
            if key not in data:
                conn = self._connections.pop(key)
                conn.keep_running = False
                conn.join()
                self.emit('connection-deleted', conn.key)

    def shutdown(self):
        for key in list(self._connections):
            conn = self._connections.pop(key)
            conn.keep_running = False
            conn.join()

    def get_connections(self):
        return self._connections.values()

    def get_connection(self, key):
        return self._connections.get(key, None)

    def get_available_drivers(self):
        return get_available_drivers()

    def test_connection(self, data):
        conn = Connection(None, data)
        try:
            conn.open()
            return True
        except Exception as err:
            return str(err).strip()

    def update_connection(self, data):
        if 'key' not in data:
            data['key'] = str(uuid.uuid4()).replace('-', '')
        key = data.pop('key')
        if os.path.exists(CONNECTIONS_FILE):
            with open(CONNECTIONS_FILE) as f:
                content = json.load(f)
        else:
            content = {}
        password = data.pop('password', None)
        content[key] = data
        with open(CONNECTIONS_FILE, 'w') as f:
            json.dump(content, f)
        if password is not None:
            data['password'] = password
            conn = self.get_connection(key)
            if not (conn and conn.has_session_password()):
                keyring.set_password('runsqlrun', key, password)
        self.update_connections()
        return key

    def delete_connection(self, key):
        with open(CONNECTIONS_FILE) as f:
            content = json.load(f)
        if key in content:
            del content[key]
            with open(CONNECTIONS_FILE, 'w') as f:
                json.dump(content, f)
        self.update_connections()