# cavaliba - sirene - field.py


from app_data.models import FIELD_FORMAT_CHOICE
from app_home.log import ERROR, log
from django.conf import settings

# --------------------------------------------------------
#  INSTANCE FIELDS
# --------------------------------------------------------

def split_composite(data):
    # Transform a data struct in flat list = [a,b,c,d,]
    # struct can be any "a,b,c" or [a , [b,c,], d, ...]

    reply = []

    if type(data) is str:
        result = [x.strip() for x in data.split(',')]
        reply += result

    elif type(data) is list:
        for g in data:
            reply += split_composite(g)

    elif type(data) is dict:
        pass

    else:
        result = [data]
        reply += result

    return reply


class Field:

    # self.fieldname
    # self.fieldschema = {...}
    # self.value = []
    # self.errors

    def __init__(self, fieldname=None, fieldschema=None, alljson=None):

        # to overload in subclass:
        # def __init__(self, fieldname, fieldschema, alljson):
        #     super().__init__(fieldname, fieldschema, alljson)

        #  removed 3.15.7
        #self.fieldschema = fieldschema

        self.fieldname = fieldname

        self.displayname = fieldschema.get("displayname", fieldname)
        self.dataformat = fieldschema.get("dataformat", "string")
        self.dataformat_ext = fieldschema.get("dataformat_ext", "")
        self.cardinal_min = fieldschema.get("cardinal_min", 0)
        self.cardinal_max = fieldschema.get("cardinal_max", 1)
        self.is_enabled = fieldschema.get("is_enabled", True) in settings.TRUE_LIST
        self.value = []
        self.default_value = fieldschema.get("default_value", None)
        self.order = fieldschema.get("order", 100)
        self.page = fieldschema.get("page", "Data")
        self.description = fieldschema.get("description", "")

        # external, schema, enumerate, external_schema, external_enumerate
        # self.is_injected = False
        # self.injected_type = ""
        self.is_injected = fieldschema.get("is_injected", False)
        self.injected_type = fieldschema.get("injected_type", "")
        self.errors = []

        # default from schema is a "ui string" ; need to convert to a list
        # self.default_value = [self.default_value]

        # json value is already a list : either from DB
        # or from merge_new_post_request POST.getlist()

        # set value from json
        if alljson:
            self.value = alljson.get(fieldname, None)
            if type(self.value) is not list:
                self.value = []
        #  else set value to default_value
        else:
            if self.default_value:
                if type(self.default_value) is list:
                    self.value = self.default_value
                else:
                    self.value = [self.default_value]


        # if exists, with mandatory value / none set / default available
        if self.cardinal_min > 0:
            if len(self.value) == 0:
                if self.default_value:
                    if type(self.default_value) is list:
                        self.value = self.default_value
                    else:
                        self.value = [self.default_value]


    def print(self):
        try:
            # value_str = '|'.join(self.value)
            print(f"  Field: {self.fieldname} = {self.value}")
        except Exception:
            pass


    def is_multi(self):
        return self.cardinal_max != 1


    def is_field_true(self):
        # overload in boolean, else ...
        return False



    def get_eav_list(self):
        ''' 
        OUT: list of string from self.value for DB DataEAV value field
        '''
        try:
            return [str(i) for i in self.value]
        except Exception:
            return ['?']


    def get_eav_format(self):
        return self.dataformat


    # TODO : split raw/processed field
    def get_attribute(self):
        # RAW return of JSON self.value = ["a", "b", ..."]
        return self.value

    def get_value(self):
        return self.value

    # return first value / process in overload
    def get_first_value(self):
        try:
            return self.value[0]
        except Exception:
            return ""


    def get_cardinal3(self):

        cardinal = len(self.value)
        cardinal_min = self.cardinal_min
        cardinal_max = self.cardinal_max

        return cardinal, cardinal_min, cardinal_max



    def get_datapoint_ui_detail(self):

        datapoint = {}
        datapoint["fieldname"] = self.fieldname
        datapoint["displayname"] = self.displayname
        datapoint["description"] = self.description
        datapoint["dataformat"] = self.dataformat
        datapoint["dataformat_ext"] = self.dataformat_ext
        datapoint["is_multi"] = self.is_multi()
        datapoint["cardinal_min"] = self.cardinal_min
        datapoint["cardinal_max"] = self.cardinal_max
        datapoint["bigset"] = False
        datapoint["value"] = ''


        if self.value:
            if len(self.value) == 1:
                datapoint["value"] = self.value[0]
            elif len(self.value) > 1:
                # TODO : join self.value.display only
                try:
                    #datapoint["value"] = ', '.join(str(self.value))
                    datapoint["value"] = ', '.join([str(z) for z in self.value])
                    #datapoint["value"] = 'XXX'
                except Exception:
                    pass

        return datapoint



    def get_datapoint_ui_edit(self):

        # default / parent behavior
        # surcharged in subclass

        df = self.dataformat
        if df not in dict(FIELD_FORMAT_CHOICE):
            log(ERROR, app="data", view="field", action="get_datapoint_ui_edit", status="KO",
                data=f"unknown dataformat '{df}' for field '{self.fieldname}' - fallback to unknown")
            df = "unknown"

        datapoint = {}
        datapoint["fieldname"] = self.fieldname
        datapoint["displayname"] = self.displayname
        datapoint["description"] = self.description
        datapoint["dataformat"] = df
        datapoint["dataformat_ext"] = self.dataformat_ext
        datapoint["is_multi"] = self.is_multi()
        datapoint["value"] = self.value

        return datapoint


    def get_datapoint_for_export(self):

        if not self.is_multi():
            try:
                return self.value[0]
            except Exception:
                # empty
                return ''
        return self.value


    def get_csv_cell(self):
        if not self.is_multi():
            try:
                return self.value[0]
            except Exception:
                # empty
                return ''
        else:
            try:
                return '^'.join(self.value)
            except Exception:
                return ''

        return self.value


    # MERGE REQUEST
    #  -------------
    def merge_request(self, request):

        # default
        data = request.POST.getlist(self.fieldname, default=[])

        self.value = []

        # default behavior
        if not data:
            return

        if len(data) == 0:
            return

        if type(data) is not list:
            try:
                if len(data) > 0:
                    self.value = [data]
            except Exception:
                return
        else:
            for i in data:
                if len(i) > 0:
                    self.value.append(i)


    #  IMPORT
    # ------
    def merge_import(self, data):
        # default behavior
        self.value = split_composite(data)



    def is_valid(self):

        # check cardinality
        cardinal = len(self.value)
        if cardinal < self.cardinal_min:
            return False
        if self.cardinal_max > 0 and cardinal > self.cardinal_max:
            return False

        return True
