from app import db
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy import ForeignKey
from uuid import uuid4
from datetime import datetime
import pandas as pd


class Dataset(db.Model):
    __tablename__ = 'dataset'
    uid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
    data = db.Column(JSONB)
    name = db.Column(db.String)
    created_date = db.Column(db.DateTime, default=datetime.now())
    modified_date = db.Column(db.DateTime, default=datetime.now())

    def __repr__(self):
        return f'<Dataset {self.uid}>'

    def from_dict(self, dct):
        for field in ['data', 'created_date', 'modified_date']:
            if field in dct:
                setattr(self, field, dct[field])
        setattr(self, 'name', dct['data']['name'])

    def to_dict(self, keys=['uid', 'created_date', 'modified_date', 'data', 'name']):
        dct = {'uid': str(self.uid), 'created_date': str(self.created_date), 'data': self.data, 'name': self.name,
               'modified_date': str(self.modified_date)}
        out = {}
        for key in keys:
            out[key] = dct[key]
        return out


class RuleGroup(db.Model):
    __tablename__ = 'rulegroup'
    uid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
    name = db.Column(db.String)
    rules = db.Column(JSONB)
    created_date = db.Column(db.DateTime, default=datetime.now())
    modified_date = db.Column(db.DateTime, default=datetime.now())
    other = db.Column(JSONB)

    def __repr__(self):
        return f'<RuleGroup {self.uid}>'

    def from_dict(self, dct):
        for field in ['name', 'rules', 'created_date', 'modified_date', 'other']:
            if field in dct:
                setattr(self, field, dct[field])
        return self

    def to_dict(self):
        dct = {'uid': str(self.uid), 'name': self.name, 'created_date': str(self.created_date), 'rules': self.rules,
               'modified_date': str(self.modified_date), 'other': self.other}
        return dct

    def get_name(self):
        return self.name


class Validation(db.Model):
    __tablename__ = 'validation'
    uid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
    rid = db.Column(db.String)
    rgid = db.Column(UUID(as_uuid=True), ForeignKey('rulegroup.uid'), default=uuid4)
    dsid = db.Column(UUID(as_uuid=True), ForeignKey('dataset.uid'), default=uuid4)
    responsible = db.Column(JSONB)
    validated = db.Column(db.Boolean)
    created_date = db.Column(db.DateTime, default=datetime.now())
    modified_date = db.Column(db.DateTime, default=datetime.now())

    def __repr__(self):
        return f'<Validation {self.uid}>'


class Rule(db.Model):
    __tablename__ = 'rule'
    uid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
    rule = db.Column(JSONB)
    name = db.Column(db.String)
    project_id = db.Column(db.String)
    created_date = db.Column(db.DateTime, default=datetime.now())
    modified_date = db.Column(db.DateTime, default=datetime.now())

    def from_dict(self, dct):
        for field in ['uid', 'rule', 'project_id', 'created_date', 'modified_date']:
            if field in dct:
                setattr(self, field, dct[field])
        setattr(self, 'name', dct['rule']['rule_attributes']['name'])
        return self

    def to_dict(self, flat=True):
        dct = {'uid': str(self.uid), 'rule': self.rule, 'created_date': str(self.created_date),
               'project_id': self.project_id, 'modified_date': str(self.modified_date), 'name': self.name}
        if flat:
            return self.rule_flatter(dct)
        return dct

    @staticmethod
    def rule_flatter(unflat_dct):
        dct = unflat_dct.copy()
        r = dct.pop('rule')
        rr = r.pop('rule_attributes')
        r.update(rr)
        dct.update(pd.json_normalize(r).to_dict(orient='records')[0])
        return dct
