#!/usr/bin/env python
# -*- coding: utf-8 -*-


import sqlite3 as sqlite
import os
import logging
import sys

from .utils import confdir

logger = logging.getLogger(__name__)


class DatabaseSqlite(object):
    ###############################################
    #               Special Methods               #
    ###############################################

    def __init__(self, file):
        self._path_file = file

        self._connection = sqlite.connect(self._path_file)
        self._cursor = self._connection.cursor()

    def __enter__(self):
        logger.debug("Open database (location: {})".format(self._path_file))

        return self

    def __exit__(self, exception_type, exception_value, traceback):
        logger.debug("Close database")

        if exception_type is not None:
            logger.debug("Got {} with value {}\nTraceback: {}".format(exception_type, exception_value, traceback))

        self._cursor.close()
        self._connection.close()

    ###############################################
    #               Private Methods               #
    ###############################################

    def _execute(self, cmd):
        """
        Method to operate in the database

        :param cmd: command to use in the database
        :return: columns + items line by line in a list(dict)
        """
        self._cursor.execute(cmd)
        self._connection.commit()

        if self._cursor.description:
            # Get all items
            select = self._cursor.fetchall()
            # Get tag of columns
            rows = [row[0] for row in self._cursor.description]

            # Now create a list which contains dict
            # Each element of the list is a line
            elements = list()
            for ele in select:
                j = 0
                new_element = dict()
                for row in ele:
                    new_element[rows[j]] = row
                    j += 1

                elements.append(new_element)

            return elements
        else:
            return None


class DontPanicDB(DatabaseSqlite):
    ###############################################
    #               CLASS CONSTANTS               #
    ###############################################

    DPDB = os.path.join(confdir, "databaz.db")

    ###############################################
    #               Special Methods               #
    ###############################################

    def __init__(self, file=DPDB):
        super(DontPanicDB, self).__init__(file)

    def __enter__(self):
        self._create_tables()

        return super(DontPanicDB, self).__enter__()

    def __repr__(self):
        """
        With this method, we can do:
            print(self)
        """
        # Print the location
        display = "Database location: {}\n".format(self._path_file)

        # Print users
        select = self._execute("SELECT login FROM users;")
        if select:
            for user in select:
                display += "User: {}".format(user["login"])

                # Print watchlist user movie
                select = self._execute("SELECT title, datetime FROM watchlist_movie "
                                       "WHERE userid=(SELECT id FROM users WHERE login='{}');".format(user["login"]))
                if select:
                    display += "\nWatchlist:\n"
                    for data in select:
                        display += "\t(Movie) {} [{}]\n".format(data["title"], data["datetime"])
                else:
                    display += "\n\tNo movie in watchlist\n"

                # Print watchlist user serie
                select = self._execute("SELECT title, datetime FROM watchlist_serie "
                                       "WHERE userid=(SELECT id FROM users WHERE login='{}');".format(user["login"]))
                if select:
                    for data in select:
                        display += "\t(Serie) {} [{}]\n".format(data["title"], data["datetime"])
                else:
                    display += "\n\tNo serie in watchlist"

                display += "\n"
        else:
            display += "Users: None"

        return display

    def _create_tables(self):
        self._execute("CREATE TABLE IF NOT EXISTS users "
                      "(id INTEGER PRIMARY KEY AUTOINCREMENT, "
                      "login VARCHAR(40) UNIQUE, "
                      "pw VARCHAR(255));")
        self._execute("CREATE TABLE IF NOT EXISTS watchlist_movie "
                      "(userid INTEGER, "
                      "title VARCHAR(255), "
                      "datetime DATE, "
                      "magnet TEXT);")
        self._execute("CREATE TABLE IF NOT EXISTS watchlist_serie "
                      "(userid INTEGER, "
                      "title VARCHAR(255), "
                      "datetime DATE, "
                      "magnet TEXT);")
        self._execute("CREATE TABLE IF NOT EXISTS recent_search "
                      "(userid INTEGER, "
                      "title VARCHAR(255), "
                      "year INTEGER, "
                      "poster VARCHAR(255), "
                      "isserie INTEGER, "
                      "datetime DATE);")

    def _get_user_id(self, user):
        """Return the user id from the users table"""
        return self._execute("SELECT id FROM users WHERE login='{}';".format(user))[0]["id"]

    ##############################################
    #               Public Methods               #
    ##############################################

    def add_user(self, user, pw):
        if not self.is_user_in(user):
            logger.debug("Add {} in the database".format(user))

            self._execute("INSERT INTO users(login, pw) VALUES('{}','{}');".format(user, pw))

            return True
        else:
            return False

    def delete_user(self, user):
        if self.is_user_in(user):
            logger.debug("Remove {} of the database".format(user))

            self._execute("DELETE FROM users WHERE login='{}';".format(user))

            return True
        else:
            return False

    def check_login(self, user, pw):
        select = self._execute("SELECT count(*) FROM users WHERE login='{}' AND pw='{}';".format(user, pw))

        if select == 1:
            return True
        else:
            return False

    def add2watchlist(self, user, title, magnet="", serie="0"):
        """
        Add an entry to watchlist of username

        Args:
            user (str): Username of the owner of watchlist
            title (str): Title to add to watchlist
            magnet (str): URL of that title
            serie (str): Specify if this is a serie (serie = 1) or a movie (serie = 0)
        """
        if not self.is_title_in_wl(user, title):
            logger.debug("Add {} on the watchlist of {} in the database".format(title, user))

            if serie == "1":
                self._execute("INSERT INTO watchlist_serie(userid, title, datetime, magnet) "
                              "VALUES('{}', '{}', date('now'), '{}')".format(self._get_user_id(user), title, magnet))
            else:
                self._execute("INSERT INTO watchlist_movie(userid, title, datetime, magnet) "
                              "VALUES('{}', '{}', date('now'), '{}')".format(self._get_user_id(user), title, magnet))

    def add2recent(self, user, title, year, poster, serie=0):
        """
        Add an entry to recently searched

        Args:
            user (str): Username of the user
            title (str): Title to add to recently searched
            year (str): Year of that title
            poster (str): TODO
            serie (bool): Specify if this is a serie (serie = 1) or a movie (serie = 0)
        """
        nb = self._execute("SELECT count(*) AS nb FROM recent_search WHERE userid='{}' "
                           "AND title='{}' AND year='{}';".format(self._get_user_id(user), title, year))[0]["nb"]
        if nb == 0:
            logger.debug("Add {} on the recently searched of {} in the database".format(title, user))
            self._execute("INSERT OR REPLACE INTO recent_search(userid, title, year, poster, isserie, datetime) "
                          "VALUES('{}', '{}', '{}', '{}', '{}', date('now'))".format(self._get_user_id(user),
                                                                                     title, year, poster, serie))

    def is_title_in_wl(self, user, title):
        nb = self._execute("SELECT count(*) AS nb FROM watchlist_movie "
                           "WHERE userid='{}' AND title='{}';".format(self._get_user_id(user), title))[0]["nb"]
        nb += self._execute("SELECT count(*) AS nb FROM watchlist_serie "
                            "WHERE userid='{}' AND title='{}';".format(self._get_user_id(user), title))[0]["nb"]

        if nb > 0:
            logger.debug("{} has already been seen by {}".format(title, user))

            return True
        else:
            return False

    def is_title_in_recent(self, user, title):
        nb = self._execute("SELECT count(*) AS nb FROM recent_search "
                           "WHERE userid='{}' AND title='{}';".format(self._get_user_id(user), title))[0]["nb"]

        if nb > 0:
            logger.debug("{} has already been searched by {}".format(title, user))

            return True
        else:
            return False

    def is_user_in(self, user):
        selection = self._execute("SELECT login FROM users WHERE login='{}';".format(user))

        if selection:
            if selection[0]["login"] == user:
                logger.debug("{} user is already in the database".format(user))

                return True
            else:
                return False
        else:
            return False

    def get_watchlist(self, user):
        if self.is_user_in(user):
            watchlist = list()
            select = self._execute("SELECT datetime, title, magnet FROM watchlist_movie "
                                   "WHERE userid='{}';".format(self._get_user_id(user)))
            watchlist.append({"list": select, "type": "movie"})

            select = self._execute("SELECT datetime, title, magnet FROM watchlist_serie "
                                   "WHERE userid='{}';".format(self._get_user_id(user)))
            watchlist.append({"list": select, "type": "serie"})

            return watchlist
        else:
            return []

    def get_recent_search(self, user):
        maxresults = 20
        if self.is_user_in(user):
            select = self._execute("SELECT title, year, poster, isserie FROM recent_search WHERE userid='{}' "
                                   "ORDER BY datetime LIMIT '{}';".format(self._get_user_id(user), maxresults))

            return select
        else:
            return []

    def delete_title_in_wl(self, user, title):
        if self.is_title_in_wl(user, title):
            logger.debug("Delete {} of the watchlist of {}".format(title, user))
            self._execute("DELETE FROM watchlist_movie WHERE userid='{}' "
                          "AND title='{}';".format(self._get_user_id(user), title))
            self._execute("DELETE FROM watchlist_serie WHERE userid='{}' "
                          "AND title='{}';".format(self._get_user_id(user), title))

    def toggle_in_wl(self, user, title, serie="1"):
        if self.is_title_in_wl(user, title):
            self.delete_title_in_wl(user, title)
        else:
            self.add2watchlist(user, title, serie=serie)

    def remove_in_recent(self, user, title):
        if self.is_title_in_recent(user, title):
            logger.debug("Delete {} of the recent list of {}".format(title, user))
            self._execute("DELETE FROM recent_search WHERE userid='{}' "
                          "AND title='{}';".format(self._get_user_id(user), title))

    #######################################
    #               Getters               #
    #######################################

    @property
    def path_file(self):
        return self._path_file


if __name__ == '__main__':
    user = 'xavier'
    with DontPanicDB() as mydb:
        print(mydb)

        if not mydb.is_user_in(user):
            print("User {} is not in db. Now add it!".format(user))
            mydb.add_user(user, "0123456789")

        name = 'the flash s02e05'
        if not mydb.is_title_in(user, name):
            print("{} is not in db. Now add it!".format(name))
            mydb.add2watchlist(user, name, serie=1)
        else:
            print("{} is already in db.".format(name))

        mydb.get_watchlist(user)

# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
