from ..base import BaseView, BaseViewException
from ..models.magasin import Adresse as Mod_Adresse
from peewee import DoesNotExist, IntegrityError
from median.database import mysql_db
import logging

logger = logging.getLogger('median')


class AdresseView(BaseView):
    """Gestion des adresses dans Median"""

    def __init__(self, adr=None, mag=None, form=None):
        """Initialise une adresse"""
        self.adresse = adr
        self.magasin = mag
        self.format = form or 'BOITE PASS'
        self.etat = 'L'

    def creer(self):
        """Creation d'une adresse"""
        if self.magasin is None:
            raise BaseViewException("Le magasin est manquant")

        try:
            adr = Mod_Adresse()
            adr.magasin = self.magasin
            adr.adresse = self.adresse
            adr.format = self.format
            adr.etat = self.etat
            adr.save()
            self.id = adr.pk
            logger.info('Création adresse "%s", magasin "%s"' % (self.adresse, self.magasin))
        except IntegrityError:
            logger.error('Erreur création adresse "%s", magasin "%s" en doublons' % (self.adresse, self.magasin))
            raise BaseViewException("Erreur doublons, création annulée !")

    def supprimer(self):
        """Suppression d'un emplacement"""
        try:
            adr = Mod_Adresse.get(adresse=self.adresse)
            adr.delete_instance()
            logger.info('Suppression adresse "%s", magasin "%s"' % (self.adresse, self.magasin))
        except DoesNotExist:
            logger.error('Erreur suppression adresse "%s" ' % self.adresse)
            raise BaseViewException("Emplacement '%s' n'existe pas " % (self.adresse or '-'))

        return True


class EmplacementView(BaseView):
    """Objet metier Emplacement"""

    def __init__(self, mag=None):
        """
        Initialise un emplacement

        :param mag: Magasin pour l'emplacement
        :type  mag: str
        :return: None
        """
        self.magasin = mag

    # Fonction générique

    def creer(self):
        """
        Il n'est pas possible de créer un emplacement, ilf aut créer une adresse
        à la place (evolution possible dans le futur)

        :raises: BaseViewException
        """
        raise BaseViewException("Un emplacement ne peut être créer, il faut créer un adresse à la place")

    # Fonction personnalisée
    def libre(produit=None, magasin=None, cformat=None, creation=False):
        """
        Recherche une adresse de libre:
        - les 2 profondeurs sont libres
        - Les emplacements 1 profondeur de dispo
        - filtrage par format de contenant
        - Si produit alors est qu'une des 2 profondeurs est libre

        Executer en SQL Pur, car des combinaisons ne sont pas possibles

        :param produit: Code produit a rechercher
        :type  produit: str
        :param magasin: Code du magasin
        :type  magasin: str
        :param cformat: Format du contenant (voir f_format)
        :type  cformat: str
        :return: La liste des emplacements
        :rtype: list
        """
        if produit is None and magasin is None and cformat is None:
            query = """
              SELECT a.x_pk AS id, a.x_adr as adresse
                FROM  f_adr a
               WHERE a.x_etat='L'
               GROUP BY left(a.x_adr, length(a.x_adr) - 4)
              HAVING count(*)=2
               UNION
              SELECT a.x_pk AS id, a.x_adr as adresse
                FROM (SELECT x_adr, x_etat, count(*) FROM f_adr WHERE x_format='BOITE PASS'
                GROUP BY left(x_adr, length(x_adr) - 4) HAVING count(*) = 1) t
               INNER JOIN f_adr a ON (a.x_adr = t.x_adr)
               WHERE t.x_etat='L'
               ORDER BY 1
            """
            cr = mysql_db.execute_sql(query)
        else:
            extra_mag = '-- pas de magasin'
            extra_pro = '-- pas de produit'
            extra_fmt = '-- pas de format'
            extra_create = "('L')"
            if magasin is not None:
                extra_mag = " AND a.x_mag = '%s' " % BaseView._protect(magasin)
            if produit is not None:
                extra_pro = " AND s.x_ref = '%s' " % BaseView._protect(produit)
            if cformat is not None:
                extra_fmt = " AND a.x_format = '%s' " % BaseView._protect(cformat)
            if creation:
                extra_create = "('L','O')"

            query = """
                SELECT a.x_pk AS id, a.x_adr as adresse
                  FROM f_adr a
                 WHERE a.x_etat='L'
                 {0}
                 {2}
                 GROUP BY left(a.x_adr, length(a.x_adr) - 4)
                HAVING count(*)=2
            UNION
                SELECT a.x_pk AS id, a.x_adr as adresse
                  FROM (SELECT x_adr, x_etat, count(*) FROM f_adr WHERE x_format='boite pass'
                 GROUP BY left(x_adr, length(x_adr) - 4) HAVING count(*) = 1) t
                 INNER JOIN f_adr a ON (a.x_adr = t.x_adr)
                 WHERE t.x_etat='L'
                 {0}
                 {2}
            UNION
                SELECT a.x_pk AS id, a.x_adr AS adresse
                FROM f_stock s
                INNER JOIN f_adr a ON left(a.x_adr, length(a.x_adr) -4 ) = left(s.x_adr,length(a.x_adr) - 4)
                WHERE a.x_etat IN {3}
                  {0}
                  {1}
                  {2}
                ORDER BY 2
            """.format(extra_mag, extra_pro, extra_fmt, extra_create)
            cr = mysql_db.execute_sql(query)

        column_names = [x[0] for x in cr.description]
        return [dict(zip(column_names, row)) for row in cr.fetchall()]


Adresse = AdresseView
Emplacement = EmplacementView
