from PyQt5.QtWidgets import QDialog
from PyQt5.QtGui import QColor, QFont

from ui.ui_member import Ui_Member
from ui.ui_search import Ui_Search
from ui.dialogs import dialog_error

from sql.models import Member, Group, CategoryMember, CategoryGroup
from sql.connection import session

import re
from datetime import date
import logging

logger = logging.getLogger('member')


class MemberCreate(QDialog, Ui_Member):
    def __init__(self, *args, **kwargs):
        self.category = kwargs.pop('category', None)
        super().__init__(*args, **kwargs)
        Ui_Member.setupUi(self, self)
        self.CreateButton.clicked.connect(self.__save)
        self.CancelButton.clicked.connect(self.reject)

    def __save(self):
        try:
            args = {
                'member_id': Member.next(),
                'first_names': self.__name(self.NamesEdit),
                'last_names': self.__name(self.SurnamesEdit),
                'birthday': self.__birthday(),
                'gender': self.GenderCombobox.value(),
                'dojo_id': self.DojoCombobox.value(),
            }
        except ValueError as err:
            dialog_error(self, 'Error alumno', str(err))
            return

        logger.info('Creating new member: %s' % repr(args))
        record = Member(**args)
        if self.category and (
                record.age not in self.category.ages() or
                record.gender not in self.category.genders()):
            dialog_error(self, 'Error alumno',
                         'Edad o sexo de alumno no corresponde con categoría.')
            return

        self.record = record
        self.accept()

    def __name(self, edit):
        v = edit.text()
        if not v or not v.isprintable():
            raise ValueError('Nombres o apellidos invalido.')
        return v

    def __birthday(self):
        rgx = re.compile(r'(?P<d>\d{1,2})[\.\-/](?P<m>\d{1,2})[\.\-/](?P<y>\d{4})$')
        m = rgx.match(self.BirthdayEdit.text())
        if not m:
            raise ValueError(
                'Fecha de nacimiento es invalida.\nFormato valido: dd-mm-YYYY')

        args = [int(a) for a in m.groups()]
        birthday = date(int(m['y']), int(m['m']), int(m['d']))
        diff = date.today() - birthday
        if diff.days < (3 * 365):
            raise ValueError(
                'Fecha de nacimiento debe ser mayor de tres años.')

        return birthday

    def exec_(self, save=True, **kwargs):
        """
        If the category is passed, check if this member matches otherwise print error
        and allow the user to update the member's data
        """
        rc = QDialog.exec_(self)
        if rc and save:
            member_id = self.record.member_id
            logger.warning('Creating new user member_id %i' % member_id)
            self.record.save()
            # -- Query again to avoid "not bound" exception when accessing the record
            self.record = session().query(Member).filter(
                Member.member_id==member_id,
            ).first()
        return rc


class RecordSearchBase(QDialog, Ui_Search):
    def __init__(self, *args, **kwargs):
        category = kwargs.pop('category', None)
        super().__init__(*args, **kwargs)
        Ui_Search.setupUi(self, self)
        self.SearchButton.clicked.connect(self.do_search)
        self.SelectButton.clicked.connect(self.__select)
        self.SelectButton.setEnabled(False)
        self.CancelButton.clicked.connect(self.reject)

        self.RecordsTable.clicked.connect(self.__clicked)
        self.RecordsTable.setColumns(self.COLUMNS)

        self.category = category
        self.title.setText(self.TITLE)
        self.setWindowTitle(self.TITLE)

    def __select(self):
        record_id = self.RecordsTable.current()
        if not record_id:
            return

        record = self.get_record(record_id)
        if self.category:
            try:
                self.category_valid(record, self.category)
            except ValueError as err:
                dialog_error(self, 'Error', str(err))
                return

        self.record = record
        self.accept()

    def __clicked(self, index):
        self.SelectButton.setEnabled(True)


class MemberSearch(RecordSearchBase):

    TITLE = 'Buscar alumno'
    COLUMNS = {
        'first_names': ('Nombres', QColor(255, 255, 255)),
        'last_names': ('Apellidos', QColor()),
        'dojo' : ('Dojo', QColor()),
        'birthday' : ('Fecha nac.', QColor()),
        'gender_text': ('Sexo', QColor()),
        'member_id': ('Id', QColor()),
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_search(self):
        self.SelectButton.setEnabled(False)
        query = session().query(Member)
        if (text := self.NamesEdit.text()):
            query = query.filter(Member.first_names.ilike(f"%{text}%"))
        if (text := self.SurnamesEdit.text()):
            query = query.filter(Member.last_names.ilike(f"%{text}%"))
        if (dojo_id := self.DojoCombobox.value(do_raise=False)):
            query = query.filter(Member.dojo_id==dojo_id)
        if (gender := self.GenderCombobox.value(do_raise=False)):
            query = query.filter(Member.gender==gender)

        self.RecordsTable.show(query.order_by('first_names'))

    def category_valid(self, record, category):
        if record.age not in category.ages():
            raise ValueError(
                'Edad de alumno es %i y no corresponde con categoría.' % record.age
            )
        elif record.gender not in category.genders():
            raise ValueError(
                'Sexo de alumno no corresponde con categoría.'
            )
        elif session().query(CategoryMember).filter(
                CategoryMember.member_id==record.member_id,
                CategoryMember.category_id==category.category_id).count():
            raise ValueError('Alumno ya está inscrito en categoría.')

    def get_record(self, index):
        return session().query(Member).filter(Member.member_id==index).first()


class GroupSearch(RecordSearchBase):

    TITLE = 'Buscar grupo'
    COLUMNS = {
        'name': ('Nombres', QColor(255, 255, 255)),
        'dojo' : ('Dojo', QColor()),
        'group_id' : ('Grupo', QColor()),
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_search(self):
        self.SelectButton.setEnabled(False)
        query = session().query(Group)
        if (text := self.NamesEdit.text()):
            query = query.filter(Group.name.ilike(f"%{text}%"))
        if (dojo_id := self.DojoCombobox.value(do_raise=False)):
            query = query.filter(Group.dojo_id==dojo_id)

        self.RecordsTable.show(query.order_by('name'))

    def category_valid(self, record, category):
        if session().query(CategoryGroup).filter(
                CategoryGroup.group_id==record.group_id,
                CategoryGroup.category_id==category.category_id).count():
            raise ValueError('Grupo ya está inscrito en categoría.')

    def get_record(self, index):
        return session().query(Group).filter(Group.group_id==index).first()
