
"""
Plugin for making an asset library of all  blender file found in a folder
"""

import re
from pathlib import Path
from itertools import groupby
import uuid
import os
import shutil
import json
import urllib3
import traceback
import time

import bpy
from bpy.props import (StringProperty, IntProperty, BoolProperty)

from .library_plugin import LibraryPlugin
from ..core.template import Template
from ..core.file_utils import install_module


class Kitsu(LibraryPlugin):

    name = "Kitsu"
    template_name : StringProperty()
    template_file : StringProperty()
    source_directory : StringProperty(subtype='DIR_PATH')
    #blend_depth: IntProperty(default=1)
    source_template_image : StringProperty()
    target_template_image : StringProperty()

    url: StringProperty()
    login: StringProperty()
    password: StringProperty(subtype='PASSWORD')
    project_name: StringProperty()
    
    def connect(self, url=None, login=None, password=None):
        '''Connect to kitsu api using provided url, login and password'''

        gazu = install_module('gazu')
        urllib3.disable_warnings()

        if not self.url:
            print(f'Kitsu Url: {self.url} is empty')
            return

        url = self.url
        if not url.endswith('/api'):
            url += '/api'

        print(f'Info: Setting Host for kitsu {url}')
        gazu.client.set_host(url)

        if not gazu.client.host_is_up():
            print('Error: Kitsu Host is down')

        try:
            print(f'Info: Log in to kitsu as {self.login}')
            res = gazu.log_in(self.login, self.password)
            print(f'Info: Sucessfully login to Kitsu as {res["user"]["full_name"]}')
            return res['user']
        except Exception as e:
            print(f'Error: {traceback.format_exc()}')

    def get_asset_path(self, name, catalog, directory=None):
        directory = directory or self.source_directory
        return Path(directory, self.get_asset_relative_path(name, catalog))

    def get_asset_info(self, data, asset_path):
        
        modified = time.time_ns()
        catalog = data['entity_type_name'].title()
        asset_path = self.prop_rel_path(asset_path, 'source_directory')
        #asset_name = self.norm_file_name(data['name'])

        asset_info = dict(
            filepath=asset_path,
            modified=modified,
            library_id=self.library.id,
            assets=[dict(
                catalog=catalog,
                metadata=data.get('data', {}),
                description=data['description'],
                tags=[],
                type=self.data_type,
                #image=self.library.template_image,
                #video=self.library.template_video,
                name=data['name'])
            ]
        )
        
        return asset_info

    # def bundle(self, cache_diff=None):
    #     """Group all asset in one or multiple blends for the asset browser"""

    #     return super().bundle(cache_diff=cache_diff)

    def set_asset_preview(self, asset, asset_data):
        '''Load an externalize image as preview for an asset using the source template'''

        asset_path = self.format_path(Path(asset_data['filepath']).as_posix())

        image_path = self.find_path(self.target_template_image, asset_data, filepath=asset_path)

        if image_path:
            with bpy.context.temp_override(id=asset):
                bpy.ops.ed.lib_id_load_custom_preview(
                    filepath=str(image_path)
                )
        else:
            print(f'No image found for {self.target_template_image} on {asset.name}')
        
        if asset.preview:
            return asset.preview


    def generate_previews(self, cache=None):
        
        print('Generate previews...')

        if cache in (None, ''):
            cache = self.fetch()
        elif isinstance(cache, (Path, str)):
            cache = self.read_cache(cache)

        #TODO Support all multiple data_type
        for asset_info in cache:

            if asset_info.get('type', self.data_type) == 'FILE':
                self.generate_blend_preview(asset_info)
            else:
                self.generate_asset_preview(asset_info)

    def generate_asset_preview(self, asset_info):

        data_type = self.data_type
        scn = bpy.context.scene
        vl = bpy.context.view_layer

        asset_path = self.format_path(asset_info['filepath'])

        lens = 85

        if not asset_path.exists():
            print(f'Blend file {asset_path} not exit')
            return


        asset_data_names = {}

        # First check wich assets need a preview
        for asset_data in asset_info['assets']:
            name = asset_data['name']
            image_path = self.format_path(self.target_template_image, asset_data, filepath=asset_path)

            if image_path.exists():
                continue

            #Store in a dict all asset_data that does not have preview
            asset_data_names[name] = dict(asset_data, image_path=image_path)

        if not asset_data_names:
            print(f'All previews already existing for {asset_path}')
            return

        #asset_names = [a['name'] for a in asset_info['assets']]
        asset_names = list(asset_data_names.keys())
        assets = self.load_datablocks(asset_path, names=asset_names, link=True, type=data_type)

        print(asset_names)
        print(assets)

        for asset in assets:
            if not asset:
                continue
            
            print(f'Generate Preview for asset {asset.name}')

            asset_data = asset_data_names[asset.name]
            
            #print(self.target_template_image, asset_path)
            image_path = self.format_path(self.target_template_image, asset_data, filepath=asset_path)
            
            # Force redo preview
            # if asset.preview:
            #     print(f'Writing asset preview to {image_path}')
            #     self.write_preview(asset.preview, image_path)
            #     continue

            if data_type == 'COLLECTION':

                bpy.ops.object.collection_instance_add(name=asset.name)
                
                scn.camera.data.lens = lens
                bpy.ops.view3d.camera_to_view_selected()
                scn.camera.data.lens -= 5

                instance = vl.objects.active

                #scn.collection.children.link(asset)
                
                scn.render.filepath = str(image_path)
                scn.render.image_settings.file_format = self.format_from_ext(image_path.suffix)
                scn.render.image_settings.color_mode = 'RGBA'
                scn.render.image_settings.quality = 90


                print(f'Render asset {asset.name} to {image_path}')
                bpy.ops.render.render(write_still=True)

                #instance.user_clear()
                asset.user_clear()

                bpy.data.objects.remove(instance)

                bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)

    def fetch(self):
        """Gather in a list all assets found in the folder"""

        print(f'Fetch Assets for {self.library.name}')

        gazu = install_module('gazu')
        self.connect()

        template_file = Template(self.template_file)
        template_name = Template(self.template_name)

        project = gazu.client.fetch_first('projects', {'name': self.project_name})
        entity_types = gazu.client.fetch_all('entity-types')
        entity_types_ids = {e['id']: e['name'] for e in entity_types}

        cache = self.read_cache()

        for asset_data in gazu.asset.all_assets_for_project(project):
            asset_data['entity_type_name'] = entity_types_ids[asset_data.pop('entity_type_id')]
            asset_name = asset_data['name']

            asset_field_data = dict(asset_name=asset_name, type=asset_data['entity_type_name'], source_directory=self.source_directory)

            try:
                asset_field_data.update(template_name.parse(asset_name))
            except Exception:
                print(f'Warning: Could not parse {asset_name} with template {template_name}')

            asset_path = template_file.find(asset_field_data)
            if not asset_path:
                print(f'Warning: Could not find file for {template_file.format(asset_field_data)}')
                continue


            asset_path = self.prop_rel_path(asset_path, 'source_directory')
            asset_cache_data = dict(
                catalog=asset_data['entity_type_name'].title(),
                metadata=asset_data.get('data', {}),
                description=asset_data['description'],
                tags=[],
                type=self.data_type,
                name=asset_data['name']
            )
            
            cache.add_asset_cache(asset_cache_data, filepath=asset_path)
            

        return cache
