# -*- coding: UTF-8 -*-
from django.core.management.base import BaseCommand, CommandError
from django.core.management import call_command
from django.conf import settings
from iconolab.models import Collection, Image, ImageStats, Item, ItemMetadata
from PIL import Image as ImagePIL
import os, csv, pprint, re, json

class Command(BaseCommand):
    help = "import images from a directory into the media folder and creates item and image objects"

    def add_arguments(self, parser):
        parser.add_argument("csv_path")
        parser.add_argument(
            '--jpeg-quality',
            dest='jpeg_quality',
            default=settings.IMG_JPG_DEFAULT_QUALITY,
            help='Jpeg default quality'

        )
        parser.add_argument(
            '--encoding',
            dest='encoding',
            default='utf-8',
            help='CSV file encoding'

        )
        parser.add_argument(
            '--collection-fixture',
            dest='collection_fixture',
            default=False,
            help='loads the fixture then insert extracted data into the created collection',
        )
        parser.add_argument(
            '--collection-id',
            dest='collection_id',
            default=False,
            help='insert extracted data into the specified collection instead of trying to load a collection fixture',
        )
        parser.add_argument(
            '--metacategories-fixture',
            dest='metacategories_fixture',
            default=False,
            help='add metacategories to the created collection from a fixture file',
        )
        parser.add_argument(
            '--delimiter',
            dest='csv_delimiter',
            default=';',
            help='csv file delimiter'
        )

    def handle(self, *args, **options):
        pp = pprint.PrettyPrinter(indent=4)
        try:
            # Check we have a collection to store data into:
            source_dir = os.path.dirname(os.path.realpath(options.get("csv_path")))
            print("# Checking collection args")
            if options.get("collection_fixture"):
                print("## Finding collection json data in "+source_dir)
                fixture_path = os.path.join(source_dir, options.get("collection_fixture"))
                if not os.path.isfile(fixture_path):
                    print("### No "+options.get("collection_fixture")+".json file was found in the source directory")
                    raise ValueError("!!! Fixture file "+fixture_path+" was not found !!!")
                try:
                    with open(fixture_path) as json_fixture_file:
                        collection_data = json.loads(json_fixture_file.read())
                        if len(collection_data) != 1:
                            raise ValueError("!!! Collection fixture has either 0 or more than one item. It should only provide one and only one collection !!!")
                        if collection_data[0]["model"] != "iconolab.Collection":
                            raise ValueError("!!! Collection fixture should provide one iconolab.Collection object and nothing else. !!!")
                except ValueError as e:
                    raise ValueError("!!! JSON Data is invalid. !!!")
            elif options.get("collection_id"):
                print("## Finding collection with id "+options.get("collection_id"))
                try:
                    collection = Collection.objects.get(pk=options.get("collection_id"))
                except Collection.DoesNotExist:
                    raise ValueError("!!! Collection with primary key "+options.get("collection_id")+" was not found, aborting !!!")
            else:
                raise ValueError("!!! No collection fixture or collection id, aborting because we can't properly generate data. !!!")

            if options.get("metacategories_fixture"):
                print("## Finding metacategories fixture json data in "+source_dir)
                metacategories_fixture_path = os.path.join(source_dir, options.get("metacategories_fixture"))
                if not os.path.isfile(metacategories_fixture_path):
                    print("### No "+options.get("metacategories_fixture")+".json file was found in the source directory")
                    raise ValueError("!!! Fixture file "+metacategories_fixture_path+" was not found !!!")
                with open(metacategories_fixture_path) as metacategories_fixture_file:
                    metacategories_data = json.loads(metacategories_fixture_file.read())
                    for metacategory in metacategories_data:
                        if options.get("collection_fixture") and metacategory["fields"].get("collection", False) != collection_data[0].get("pk"):
                            print(metacategory["fields"].get("collection", False))
                            raise ValueError("!!! The fixture should only contain metacategories for the imported collection !!!")
                        elif options.get("collection_id") and metacategory["fields"].get("collection", False) != collection.id:
                            raise ValueError("!!! The fixture should only contain metacategories for the imported collection !!!")

            # We read the csv
            csvreader = csv.DictReader(open(options.get("csv_path"), encoding=options.get("encoding")), delimiter=options.get('csv_delimiter', ';'))
            print("# Extracting data from csv file and storing it in standardized format")
            # We store data using the Jocondelab keys, as defined in settings.IMPORT_FIELDS_DICT
            cleaned_csv_data=[]
            for row in csvreader:
                cleaned_row_data = {}
                for key in settings.IMPORT_FIELDS_DICT.keys():
                    cleaned_row_data[key] = ""
                    for row_key in row.keys():
                        if row_key in settings.IMPORT_FIELDS_DICT[key]:
                            cleaned_row_data[key] = row[row_key]
                            break
                cleaned_csv_data.append(cleaned_row_data)

            print("# Finding corresponding images and filtering csv data for found images")
            # Listing image files in csv directory
            image_list = [f for f in os.listdir(source_dir) if os.path.isfile(os.path.join(source_dir, f)) and not f.endswith(".csv")]
            filtered_csv_data = []
            # Now we trim the cleaned_csv_data dict to keep only entries that have at least one image
            for item in cleaned_csv_data:
                item["SRC_IMG_FILES"] = []
                has_image = False
                for image in image_list:
                    if image.startswith(item["INV"]):
                        item["SRC_IMG_FILES"].append(image)
                        has_image = True
                if has_image:
                    filtered_csv_data.append(item)
            print("## found " + str(len(filtered_csv_data))+" items with at least one image")
            print("# Importing data into Iconolab")
            if options.get("collection_fixture"):
                print("## Loading collection fixture")
                call_command("loaddata", fixture_path)
                collection = Collection.objects.get(
                    pk = collection_data[0]["pk"]
                )
                if collection.image:
                    collection_image_path = os.path.join(settings.MEDIA_ROOT, str(collection.image))
                    if not os.path.isfile(collection_image_path):
                        print("### Moving collection image")
                        _ , collection_image_name = os.path.split(collection_image_path)
                        try:
                            col_im = ImagePIL.open(os.path.join(source_dir, collection_image_name))
                            print("##### Generating or copying jpeg for "+collection_image_name)
                            col_im.thumbnail(col_im.size)
                            col_im.save(collection_image_path, "JPEG", quality=options.get("jpeg_quality", settings.IMG_JPG_DEFAULT_QUALITY))
                        except Exception as e:
                            print(e)
            if options.get("metacategories_fixture"):
                call_command("loaddata", metacategories_fixture_path)
            print("## Converting image and moving it to static dir, creating Image and Item objects")
            target_dir = os.path.join(settings.MEDIA_ROOT, "uploads")
            print("### Images will be stored in "+target_dir)
            for item in filtered_csv_data:
                print("#### Computing metadatas for item "+item["INV"]+" (inv number)")
                if not item["INV"]:
                    print("#### No INV number, skipping")
                    continue
                item_authors = item["AUTR"]
                item_school = item["ECOLE"]
                item_designation = ""
                if item.get("TITR", ""):
                    item_designation = item["TITR"]
                elif item.get("DENO", ""):
                    item_designation = item["DENO"]
                elif item.get("APPL", ""):
                    item_designation = item["APPL"]
                item_datation = ""
                if item.get("PERI", ""):
                    item_datation = item["PERI"]
                elif item.get("MILL", ""):
                    item_datation = item["MILL"]
                elif item.get("EPOQ", ""):
                    item_datation = item["EPOQ"]
                item_technics = item["TECH"]
                item_measurements = item["DIMS"]
                item_create_or_usage_location = item["LIEUX"]
                item_discovery_context = item["DECV"]
                item_conservation_location = item["LOCA"]
                item_photo_credits = item["PHOT"]
                item_inventory_number = item["INV"]
                item_joconde_ref = item["REF"]
                if ItemMetadata.objects.filter(item__collection = collection, inventory_number = item_inventory_number).exists():
                    print("#### An item with "+item["INV"]+" for inventory number, already exists in databse in the import collection")
                else:
                    print("#### Creating item "+item["INV"]+" (inv number) in databse")
                    item_object = Item.objects.create(
                        collection = collection
                    )
                    ItemMetadata.objects.create(
                        item = item_object,
                        authors = item_authors,
                        school = item_school,
                        designation = item_designation,
                        datation = item_datation,
                        technics = item_technics,
                        measurements = item_measurements,
                        create_or_usage_location = item_create_or_usage_location,
                        discovery_context = item_discovery_context,
                        conservation_location = item_conservation_location,
                        photo_credits = item_photo_credits,
                        inventory_number = item_inventory_number,
                        joconde_ref = item_joconde_ref
                    )
                    print("#### Computing item image(s)")
                    for image in item["SRC_IMG_FILES"]:
                        (image_name, ext) = os.path.splitext(image)
                        image_path = os.path.join(target_dir, image_name) + ".jpg"
                        if os.path.isfile(image_path):
                            print("##### A jpeg file already exists in target dir for "+ image)
                            try:
                                im = ImagePIL.open(image_path)
                                im_width, im_height = im.size
                            except Exception as e:
                                print(e)
                                continue
                        else:
                            jpeg_img_path = image_path
                            try:
                                im = ImagePIL.open(os.path.join(source_dir, image))
                                print("##### Generating or copying jpeg for "+image)
                                im.thumbnail(im.size)
                                im.save(jpeg_img_path, "JPEG", quality=options.get("jpeg_quality", settings.IMG_JPG_DEFAULT_QUALITY))
                                im_width, im_height = im.size
                            except Exception as e:
                                print(e)
                                continue
                        new_image = Image.objects.create(
                            item = item_object,
                            media = "uploads/"+image_name+".jpg",
                            name = image_name+".jpg",
                            height = im_height,
                            width = im_width
                        )
                        ImageStats.objects.create(
                            image = new_image
                        )
            print("# All done!")
        except FileNotFoundError:
            print("!!! File "+options.get("csv_path")+" does not exist. !!!")
        except ValueError as e:
            print(str(e))
