"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
"""
import shutil
import io
import hashlib
import json
import os
from datetime import datetime
from copy import deepcopy

from django.conf import settings
from django.db import models
from label_studio_converter import Converter
from core.utils.io import get_temp_dir, read_bytes_stream, get_all_files_from_dir
from core.label_config import parse_config
from core import version
from tasks.models import Annotation

# Create your models here.


class DataExport(object):
    @staticmethod
    def save_export_files(project, now, get_args, data, md5, name):
        """Generate two files: meta info and result file and store them locally for logging"""
        filename_results = os.path.join(settings.EXPORT_DIR, name + ".json")
        filename_info = os.path.join(settings.EXPORT_DIR, name + "-info.json")
        annotation_number = Annotation.objects.filter(task__project=project).count()
        info = {
            "project": {
                "title": project.title,
                "id": project.id,
                "created_at": project.created_at.strftime("%Y-%m-%dT%H:%M:%SZ"),
                "created_by": project.created_by.email,
                "task_number": project.tasks.count(),
                "annotation_number": annotation_number,
            },
            "platform": {"version": version.get_git_version()},
            "download": {
                "GET": dict(get_args),
                "time": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
                "result_filename": filename_results,
                "md5": md5,
            },
        }

        with open(filename_results, "w", encoding="utf-8") as f:
            f.write(data)
        with open(filename_info, "w", encoding="utf-8") as f:
            json.dump(info, f, ensure_ascii=False)
        return filename_results

    @staticmethod
    def get_export_formats(project):
        converter = Converter(config=project.get_parsed_config(), project_dir=None)
        formats = []
        supported_formats = set(converter.supported_formats)
        for format, format_info in converter.all_formats().items():
            format_info = deepcopy(format_info)
            format_info["name"] = format.name
            if format.name not in supported_formats:
                format_info["disabled"] = True
            formats.append(format_info)
        return sorted(formats, key=lambda f: f.get("disabled", False))

    @staticmethod
    def generate_export_file(project, tasks, output_format, get_args):
        # prepare for saving
        now = datetime.now()
        data = json.dumps(tasks, ensure_ascii=False)
        md5 = hashlib.md5(json.dumps(data).encode("utf-8")).hexdigest()
        name = (
            "project-" + str(project.id) + "-at-" + now.strftime("%Y-%m-%d-%H-%M") + f"-{md5[0:8]}"
        )

        input_json = DataExport.save_export_files(project, now, get_args, data, md5, name)
        converter = Converter(
            config=project.get_parsed_config(),
            project_dir=None,
            upload_dir=os.path.join(settings.MEDIA_ROOT, settings.UPLOAD_DIR),
        )
        with get_temp_dir() as tmp_dir:
            converter.convert(input_json, tmp_dir, output_format, is_dir=False)
            files = get_all_files_from_dir(tmp_dir)
            # if only one file is exported - no need to create archive
            if len(os.listdir(tmp_dir)) == 1:
                output_file = files[0]
                ext = os.path.splitext(output_file)[-1]
                content_type = f"application/{ext}"
                out = read_bytes_stream(output_file)
                filename = name + os.path.splitext(output_file)[-1]
                return out, content_type, filename

            # otherwise pack output directory into archive
            shutil.make_archive(tmp_dir, "zip", tmp_dir)
            out = read_bytes_stream(os.path.abspath(tmp_dir + ".zip"))
            content_type = "application/zip"
            filename = name + ".zip"
            return out, content_type, filename
