# -*- coding: utf-8 -*-
"""
Mirada playlist format OTIO adapter

"""

import os
import sys
import time

# File is imported directly by OTIO
try:
    from pycerebro.vista import *
except ImportError:
    from .vista import *


OTIO_VAR = "OTIO_PLUGIN_MANIFEST_PATH"
OTIO_FILE_PREFIX = "file://"
OTIO_MANIFEST = "vista.plugin_manifest.json"


def setup_otio():
	env_value = [ i for i in os.environ.get(OTIO_VAR, "").split(os.pathsep) if len(i) ]
	manifest_location = os.path.normpath(os.path.join(os.path.dirname(__file__), OTIO_MANIFEST))
	
	if not manifest_location in env_value:
		env_value.append(manifest_location)
		os.environ[OTIO_VAR] = os.pathsep.join(env_value)
		
		if "opentimelineio" in sys.modules:
			import opentimelineio as otio
			# Reload manifest
			otio.plugins.ActiveManifest(True)

def parseInt(strval, default = 0):
	try:
		return int(strval)
	except:
		return default

def read_from_file(filepath):
	import opentimelineio as otio
	from pathlib import Path
	
	timeline = otio.schema.Timeline()
	timeline.name = "Cerebro Mirada Export"
	#timeline.metadata["cerebro"] = {
	#	"taskId": ""
	#}
	
	lista = Vista()
	lista.set_lista(filepath)
	
	t_versions = ListaVersions(Vista.VERSION)
	t_files = ListaFiles(Vista.VERSION)
	t_file_ab = ListaFileAb(Vista.VERSION)
	t_file_order = ListaFileOrder(Vista.VERSION)
	t_tails = ListaTails(Vista.VERSION)
	
	qversions = lista.query(t_versions.select())
	qfiles = lista.query(t_files.select())
	qfiles_ab = lista.query(t_file_ab.select())
	qfiles_order = lista.query(t_file_order.select())
	qfiles_tails = lista.query(t_tails.select())
	
	file_ids = [ i[1] for i in sorted(qfiles_order, key=lambda fo: fo[0]) ]
	file_versions = { i[0]: (i[1], i[2]) for i in qfiles_ab }
	file_tails = { i[0]: i for i in qfiles_tails }
	files = { i[0]: i for i in qfiles }
	versions = { i[0]: i for i in qversions }
	
	for ver_num, ver_name in enumerate(['A', 'B']):
		track = otio.schema.Track()
		track.name = "Mirada Track {}".format(ver_name)
		
		frame_start = 0
		
		for file_id in file_ids:
			tail_begin = 0
			tail_end = 0
			file_duration = parseInt(files[file_id][t_files.column_of("duration")])
			file_fps = parseInt(files[file_id][t_files.column_of("fps")])
			
			# Only video/audio tracks are accepted by OTIO
			if file_duration < 2: continue
			
			if file_id in file_tails:
				tail_begin = file_tails[file_id][t_tails.column_of("at_begin")]
				tail_end = file_tails[file_id][t_tails.column_of("at_end")]
			
			ver_id = file_versions[file_id][ver_num]
			
			if ver_id is not None:
				ver_duration = parseInt(versions[ver_id][t_versions.column_of("duration")])
				ver_fps = parseInt(versions[ver_id][t_versions.column_of("fps")])
				ver_path = str(versions[ver_id][t_versions.column_of("path")])
				
				# Only video/audio tracks are accepted by OTIO
				if ver_duration < 2: continue
				
				clip = otio.schema.Clip()
				clip.name = str(versions[ver_id][t_versions.column_of("name")])
				clip.metadata["cerebro"] = {
					"file_id": str(file_id)
					, "version_id": str(ver_id)
					, "event_id": str(versions[ver_id][t_versions.column_of("event_id")])
					, "group_id": str(versions[ver_id][t_versions.column_of("group_id")])
					, "task_id": str(files[file_id][t_files.column_of("task_id")])
				}
				
				# displayed range
				clip.source_range = otio.opentime.TimeRange(
					start_time=otio.opentime.RationalTime(frame_start + tail_begin, ver_fps),
					duration=otio.opentime.RationalTime(file_duration - (tail_begin + tail_end), ver_fps)
				)
				clip.media_reference = otio.schema.ExternalReference(
					target_url=Path(ver_path).as_uri(),
					# actual file range
					available_range=otio.opentime.TimeRange(
						start_time=otio.opentime.RationalTime(frame_start, ver_fps),
						duration=otio.opentime.RationalTime(ver_duration, ver_fps)
				  )
				)
				
				track.append(clip)
			
			frame_start += file_duration + 1
		
		if len(track) > 0:
			timeline.tracks.append(track)
	
	return timeline

def write_to_file(input_otio, filepath):
	import opentimelineio as otio
	
	lista = Vista()
	lista.create_lista(lista_path=filepath)
	
	iter_file_id = (i for i in range(-3, -1000000, -1))
	iter_version_id = (i for i in range(-3, -1000000, -1))
	
	file_order = []
	file_versions = {}
	files = {}
	versions = {}
	
	if input_otio.tracks and len(input_otio.tracks):
		for track in input_otio.tracks[:2]:
			for clip in track:
				ver_name = clip.name
				ver_path = clip.media_reference.target_url
				ver_meta = clip.metadata.get("cerebro", {})
				
				ver_start = clip.source_range.start_time.value
				ver_duration = clip.source_range.duration.value
				ver_fps = clip.source_range.start_time.rate
				ver_id = ver_meta.get("version_id", next(iter_version_id))
				
				file_start = clip.visible_range().start_time.value
				file_duration = clip.visible_range().duration.value
				file_fps = clip.visible_range().start_time.rate
				
				#print(ver_name, ver_path, ver_meta)
				#print('\t', ver_start, ver_duration, ver_fps)
				#print('\t', file_start, file_duration, file_fps)
				
				ver_path = ver_path[ver_path.startswith(OTIO_FILE_PREFIX) and len(OTIO_FILE_PREFIX):].lstrip("\\/")
				if len(ver_path) > 1 and ver_path[1] != ':': ver_path = "//" + ver_path
				
				if file_start not in files:
					files[file_start] = {
						"start": file_start
						, "duration": file_duration
						, "fps": file_fps
						, "name": ver_name
						, "id": ver_meta.get("file_id", next(iter_file_id))
						, "task_id": ver_meta.get("task_id", None)
					}
					
					file_versions[files[file_start]["id"]] = []
					file_order.append(file_start)
				
				versions[ver_id] = {
					"start": ver_start
					, "duration": ver_duration
					, "fps": ver_fps
					, "name": ver_name
					, "path": ver_path
					, "id": ver_id
					, "file_id": files[file_start]["id"]
					, "group_id": ver_meta.get("group_id", None)
					, "event_id": ver_meta.get("event_id", None)
					, "id": ver_id
				}
				
				file_versions[files[file_start]["id"]].append(ver_id)
	
	#print(file_order)
	#print(file_versions)
	#print(files)
	#print(versions)
	
	for file_start in file_order:
		lista.insert_file({
			"id": files[file_start]["id"]
			, "flags": 0
			, "task_id": files[file_start]["task_id"]
			, "name": files[file_start]["name"]
			, "duration": files[file_start]["duration"]
			, "fps": files[file_start]["fps"]
		})
	
	for ver_id, version in versions.items():
		lista.insert_version({
			"id": ver_id
			, "flags": 0
			, "file_id": versions[ver_id]["file_id"]
			, "created_utc": parseInt(time.time() * 1000)
			, "name": versions[ver_id]["name"]
			, "event_id": versions[ver_id]["event_id"]
			, "group_id": versions[ver_id]["group_id"]
			, "duration": versions[ver_id]["duration"]
			, "fps": versions[ver_id]["fps"]
			, "path": versions[ver_id]["path"]
		})
	
	for file_id, ver_list in file_versions.items():
		lista.insert_ab(
			file_id
			, ver_list[0]
			, ver_list[1] if len(ver_list) > 1 else None
		)
	
	return
