﻿/* Copyright (C) Itseez3D, Inc. - All Rights Reserved
* You may not use this file except in compliance with an authorized license
* Unauthorized copying of this file, via any medium is strictly prohibited
* Proprietary and confidential
* UNLESS REQUIRED BY APPLICABLE LAW OR AGREED BY ITSEEZ3D, INC. IN WRITING, SOFTWARE DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
* See the License for the specific language governing permissions and limitations under the License.
* Written by Itseez3D, Inc. <support@avatarsdk.com>, December 2020
*/

using ItSeez3D.AvatarSdk.Core;
using ItSeez3D.AvatarSdkSamples.Core;
using ItSeez3D.AvatarSdkSamples.SamplePipelineTraits;
using System.Collections;
using System.Linq;
using UnityEngine;

namespace ItSeez3D.AvatarSdkSamples.Cloud
{
	/// <summary>
	/// Sample scene handler that encapsulates general logic of avatar creation 
	/// and some multiplayer-specific avatar management.
	/// </summary>
	public class PhotonSampleSceneHandler : GettingStartedSample
	{
		private IFullbodyAvatarProvider fullbodyAvatarProvider = null;

		private readonly string generatedHaircutName = "generated";

		public PhotonSampleSceneHandler()
		{
			selectedPipelineType = PipelineType.FIT_PERSON;
		}

		public override void GenerateRandomAvatar()
		{
			byte[] photoBytes = null;
			if (selectedPipelineType == PipelineType.META_PERSON_MALE)
				photoBytes = photoSupplier.GetMalePhoto();
			else if (selectedPipelineType == PipelineType.META_PERSON_FEMALE)
				photoBytes = photoSupplier.GetFemalePhoto();
			else
				photoBytes = photoSupplier.GetRandomPhoto();

			StartCoroutine(GenerateAvatarFunc(photoBytes));
		}

		protected override IEnumerator Initialize()
		{
			fullbodyAvatarProvider = AvatarSdkMgr.GetFullbodyAvatarProvider();
			avatarProvider = fullbodyAvatarProvider;
			yield return Await(avatarProvider.InitializeAsync());
		}
		private bool hasAvatar = false;
		protected override IEnumerator GenerateAndDisplayHead(byte[] photoBytes, PipelineType pipeline)
		{
			hasAvatar = true;

			FullbodyAvatarComputationParameters computationParameters = new FullbodyAvatarComputationParameters();

			var parametersRequest = fullbodyAvatarProvider.GetAvailableComputationParametersAsync(selectedPipelineType);
			yield return Await(parametersRequest);
			//Choose random outfit to be computed
			System.Random random = new System.Random(System.DateTime.Now.Millisecond);
			string outfitName = parametersRequest.Result.outfits.names[random.Next(parametersRequest.Result.outfits.names.Count)];
			computationParameters.outfits.names.Add(outfitName);
			computationParameters.outfits.embed = false;

			computationParameters.haircuts.names.Add(generatedHaircutName);
			computationParameters.haircuts.embed = false;

			// Generate avatar from the photo and get its code in the Result of request
			var initializeRequest = fullbodyAvatarProvider.InitializeFullbodyAvatarAsync(photoBytes, computationParameters, selectedPipelineType);
			yield return Await(initializeRequest);
			currentAvatarCode = initializeRequest.Result;

			StartCoroutine(SampleUtils.DisplayPhotoPreview(currentAvatarCode, photoPreview));

			// Wait avatar to be calculated
			var calculateRequest = fullbodyAvatarProvider.StartAndAwaitAvatarCalculationAsync(currentAvatarCode);
			yield return Await(calculateRequest);

			// Download all avatar data from the cloud and store on the local drive
			var gettingAvatarModelRequest = fullbodyAvatarProvider.RetrieveAllAvatarDataFromCloudAsync(currentAvatarCode);
			yield return Await(gettingAvatarModelRequest);

			Photon.InstatiateLocalFullbodyAvatar(currentAvatarCode, generatedHaircutName, outfitName, selectedPipelineType);
		}

		private PhotonManager Photon
		{
			get
			{
				var photonManager = GetComponent<PhotonManager>();
				if (photonManager == null)
				{
					Debug.LogFormat("{0} component should be added to game object", nameof(PhotonManager));
					return null;
				}
				return photonManager;
			}
		}
		protected override void Start()
		{
			base.Start();
			SetControlsInteractable(false);

			Photon.AvatarPlayerConnectedEvent += OnAvatarPlayerConnected;
            Photon.ConnectedToPhotonServerEvent += OnConnectedToPhotonServer;
            Photon.ConnectionErrorEvent += OnConnectionError;
		}

        private void OnConnectionError(string message)
        {
			SetControlsInteractable(false);
			progressText.text = message;
		}


		private void OnConnectedToPhotonServer()
        {
			//if no avatar is generating
            if (!hasAvatar)
            {
				SetControlsInteractable(true);
			}
		}

        //Only one avatar may be generated for player in this sample, 
        //so we disable controls when player instance have been initialized
        protected override void SetControlsInteractable(bool interactable)
		{
			if (Photon.playerInstance == null && Photon.IsConnected)
			{
				base.SetControlsInteractable(interactable);
			}
			else
			{
				base.SetControlsInteractable(false);
			}
		}

		private void OnAvatarPlayerConnected(string avatarCode, GameObject avatarObject, string haircutName, string outfitName)
		{
			StartCoroutine(DownloadAndDisplayFullbodyAvatar(avatarCode, avatarObject, haircutName, outfitName));
		}

		private IEnumerator DownloadAndDisplayFullbodyAvatar(string avatarCode, GameObject avatarObject, string haircutName, string outfitName)
		{
			var downloadModelRequest = fullbodyAvatarProvider.RetrieveBodyModelFromCloudAsync(avatarCode);
			yield return Await(downloadModelRequest);

			var downloadHaircutRequest = fullbodyAvatarProvider.RetrieveHaircutModelFromCloudAsync(avatarCode, haircutName);
			yield return Await(downloadHaircutRequest);

			var downloadOutfitRequest = fullbodyAvatarProvider.RetrieveOutfitModelFromCloudAsync(avatarCode, outfitName);
			yield return Await(downloadOutfitRequest);

			yield return Photon.InstantiateFullbodyAvatar(avatarCode, haircutName, outfitName, avatarObject, selectedPipelineType);
		}

	}
}