# (c) cavaliba.com - data - views_import.py


import yaml
from app_data.data import Instance
from app_data.filestore import tmp_local_filepath
from app_data.forms import DataUploadForm
from app_data.loader import load_broker, load_file_csv, load_file_json, load_file_yaml
from app_data.pipeline import Pipeline
from app_data.schema import Schema
from app_home.log import DEBUG, ERROR, INFO, log
from app_user.aaa import start_view
from app_user.group import group_to_yaml
from app_user.models import SireneGroup, SireneUser
from app_user.role import role_to_yaml
from django.contrib import messages
from django.shortcuts import redirect, render
from django.utils.translation import gettext as _


# -------------------------------------------------------------------------
# YAML TEXT EDITOR TOOL (global)
# -------------------------------------------------------------------------
#def texteditor(request, classname=None, keyname=None, id=None):
def texteditor(request, classname=None, id=None):

    context = start_view(request, app="data", view="texteditor",
        noauth = "app_sirene:private", perm="p_data_import", noauthz="app_home:private")
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    rawdata = ""

    # Get existing data or empty
    if request.method == "GET":

        #  no id          : => schema
        # no classname   : => instance
        # id + classname : _user, _group or _role


        # Schema
        if not id:
            schema = Schema.from_name(classname)
            try:
                rawdata = schema.to_yaml()
            except Exception:
                pass

        # Instance
        elif not classname:
            instance = Instance.from_id(id)
            #instance.print()
            if instance:
                rawdata = instance.to_yaml()

        #  special case (non Schema struct)
        elif classname == '_user':
            user = SireneUser.objects.filter(id=id).first()
            if user:
                rawdata = user.to_yaml()

        elif classname == '_group':
            group = SireneGroup.objects\
                .filter(is_role=False, id=id)\
                .prefetch_related("users")\
                .prefetch_related("subgroups")\
                .first()
            if group:
                rawdata = group_to_yaml(group)

        elif classname == '_role':
            role = SireneGroup.objects\
                .filter(is_role=True, id=id)\
                .prefetch_related("users")\
                .prefetch_related("subgroups")\
                .prefetch_related("permissions")\
                .first()
            if role:
                rawdata = role_to_yaml(role)


    elif request.method == "POST":

        valid = False
        rawdata = request.POST["rawdata"]
        datalist = None

        #  TODO: sanitize
        pipeline = None
        pipeline_name = request.POST["pipeline"]
        if pipeline_name:
            pipeline = Pipeline.from_name(pipeline_name)

        # Get TextArea
        try:
            datalist = yaml.safe_load(rawdata)
            valid = True
        except Exception as e:
            messages.add_message(request, messages.ERROR, e)

        # File provided ?
        fileform = DataUploadForm(request.POST, request.FILES)

        if fileform.is_valid():

            postfile = request.FILES["file"]

            # filestore tmp file
            filename = tmp_local_filepath()
            with open(filename, "wb+") as destination:
                for chunk in postfile.chunks():
                    destination.write(chunk)

            # if file.multiple_chunks():
            #     messages.add_message(request, messages.ERROR, _("Import failed - file too big"))
            #     log(ERROR, aaa=aaa, app="data", view="import", action="post", status="KO", data=_("Import failed - file too big"))
            #     return redirect("app_data:private")

            if postfile.name.endswith('.csv'):
                datalist = load_file_csv(filename=filename, pipeline_name=pipeline_name)

            elif postfile.name.endswith('.yml') or postfile.name.endswith('.yaml'):
                datalist = load_file_yaml(filename=filename, pipeline_name=pipeline_name)

            elif postfile.name.endswith('.json'):
                datalist = load_file_json(filename=filename, pipeline_name=pipeline_name)

            if type(datalist) is not list:
                messages.add_message(request, messages.ERROR, _("Import failed - invalid file"))
                log(ERROR, aaa=aaa, app="data", view="import", action="file", status="KO",
                    data=f"Content is not a list : {postfile.name}")
                datalist = []
            else:
                log(INFO, aaa=aaa, app="data", view="import", action="file", status="OK",
                    data=f"loaded: {postfile.name}")
                valid = True


        # check mode only
        if request.POST["submit"] == "verify":
            if valid:
                messages.add_message(request, messages.SUCCESS, _("Check ok"))
                log(DEBUG, aaa=aaa, app="data", view="import", action="check", status="OK")
            # else keep editing ...


        # submit
        if request.POST["submit"] == "import":
            if valid:

                count = 0
                for datadict in datalist:
                    count += 1
                    if pipeline:
                        status = pipeline.apply(datadict)
                        if status == 'discard':
                            continue
                    result = load_broker([datadict], aaa=aaa)
                    count += 1

                messages.add_message(request, messages.SUCCESS, _("Import OK"))
                log(DEBUG, aaa=aaa, app="data", view="import", action="import", status="OK", data=f"imported: {count} objects")
                return redirect("app_home:private")

    # edit
    context["upload_form"] = DataUploadForm()
    context["rawdata"] = rawdata
    context["pipelines"] = Pipeline.list(is_enabled=True)
    return render(request, 'app_data/import.html', context)
