﻿using System;
using System.Collections.Generic;
using UniJSON;
using UnityEngine;

namespace UniVRM10
{
    ///
    /// 互換性の無いところ
    /// 
    /// * きつくなる方向は許す
    /// * 緩くなる方向は不許可(throw)
    /// 
    // "meta": {
    //   "title": "Alicia Solid",
    //   "version": "1.10",
    //   "author": "© DWANGO Co., Ltd.",
    //   "contactInformation": "https://3d.nicovideo.jp/alicia/",
    //   "reference": "",
    //   "texture": 7,
    //   "allowedUserName": "Everyone",
    //   "violentUssageName": "Disallow",
    //   "sexualUssageName": "Disallow",
    //   "commercialUssageName": "Allow",
    //   "otherPermissionUrl": "https://3d.nicovideo.jp/alicia/rule.html",
    //   "licenseName": "Other",
    //   "otherLicenseUrl": "https://3d.nicovideo.jp/alicia/rule.html"
    // },
    public static class MigrationVrmMeta
    {
        public static UniGLTF.Extensions.VRMC_vrm.Meta Migrate(UniGLTF.glTF gltf, JsonNode vrm0)
        {
            var meta = new UniGLTF.Extensions.VRMC_vrm.Meta
            {
                LicenseUrl = Vrm10Exporter.LICENSE_URL_JA,
                AllowPoliticalOrReligiousUsage = false,
                AllowExcessivelySexualUsage = false,
                AllowExcessivelyViolentUsage = false,
                AllowRedistribution = false,
                AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.onlyAuthor,
                CommercialUsage = UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit,
                CreditNotation = UniGLTF.Extensions.VRMC_vrm.CreditNotationType.required,
                Modification = UniGLTF.Extensions.VRMC_vrm.ModificationType.prohibited,
            };

            string otherLicenseUrl = default;
            string otherPermissionUrl = default;

            foreach (var kv in vrm0.ObjectItems())
            {
                var key = kv.Key.GetString();
                switch (key)
                {
                    case "title": meta.Name = kv.Value.GetString(); break;
                    case "version": meta.Version = kv.Value.GetString(); break;
                    case "author": meta.Authors = new List<string>() { kv.Value.GetString() }; break;
                    case "contactInformation": meta.ContactInformation = kv.Value.GetString(); break;
                    case "reference": meta.References = new List<string>() { kv.Value.GetString() }; break;
                    case "texture":
                        {
                            // vrm0x use texture. vrm10 use image
                            var textureIndex = kv.Value.GetInt32();
                            if (textureIndex == -1)
                            {
                                meta.ThumbnailImage = -1;
                            }
                            else
                            {
                                var gltfTexture = gltf.textures[textureIndex];
                                meta.ThumbnailImage = gltfTexture.source;
                            }
                            break;
                        }

                    case "allowedUserName":
                        {
                            var allowedUserName = kv.Value.GetString();
                            switch (allowedUserName)
                            {
                                case "OnlyAuthor":
                                    meta.AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.onlyAuthor;
                                    break;
                                case "ExplicitlyLicensedPerson":
                                    meta.AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.onlySeparatelyLicensedPerson;
                                    break;
                                case "Everyone":
                                    meta.AvatarPermission = UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.everyone;
                                    break;
                                default:
                                    throw new NotImplementedException($"{key}: {allowedUserName}");
                            }
                        }
                        break;

                    case "violentUssageName": // Typo "Ussage" is VRM 0.x spec.
                        {
                            var violentUsageName = kv.Value.GetString();
                            switch (violentUsageName)
                            {
                                case "Allow":
                                    meta.AllowExcessivelyViolentUsage = true;
                                    break;
                                case "Disallow":
                                    meta.AllowExcessivelyViolentUsage = false;
                                    break;
                                default:
                                    throw new NotImplementedException($"{key}: {violentUsageName}");
                            }
                        }
                        break;

                    case "sexualUssageName": // Typo "Ussage" is VRM 0.x spec.
                        {
                            var sexualUsageName = kv.Value.GetString();
                            switch (sexualUsageName)
                            {
                                case "Allow":
                                    meta.AllowExcessivelySexualUsage = true;
                                    break;
                                case "Disallow":
                                    meta.AllowExcessivelySexualUsage = false;
                                    break;
                                default:
                                    throw new NotImplementedException($"{key}: {sexualUsageName}");
                            }
                        }
                        break;

                    case "commercialUssageName": // Typo "Ussage" is VRM 0.x spec.
                        {
                            var commercialUsageName = kv.Value.GetString();
                            switch (commercialUsageName)
                            {
                                case "Allow":
                                    meta.CommercialUsage = UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalProfit;
                                    break;
                                case "Disallow":
                                    meta.CommercialUsage = UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit;
                                    break;
                                default:
                                    throw new NotImplementedException($"{key}: {commercialUsageName}");
                            }
                        }
                        break;

                    case "otherPermissionUrl": otherPermissionUrl = kv.Value.GetString(); break;
                    case "otherLicenseUrl": otherLicenseUrl = kv.Value.GetString(); break;

                    case "licenseName":
                        {
                            // TODO
                            // CreditNotation = CreditNotationType.required,
                        }
                        break;

                    default:
                        Debug.LogWarning($"[meta migration] unknown key: {key}");
                        break;
                } // switch
            } // foreach

            //
            // OtherLicenseUrl migrate
            // OtherPermissionURL removed
            //
            if (!string.IsNullOrEmpty(otherLicenseUrl) && !string.IsNullOrEmpty(otherPermissionUrl))
            {
                if (otherLicenseUrl == otherPermissionUrl)
                {
                    // OK
                    meta.OtherLicenseUrl = otherLicenseUrl;
                }
                else
                {
                    // https://github.com/vrm-c/UniVRM/issues/1611
                    // 両方を記述しエラーとしない
                    meta.OtherLicenseUrl = $"'{otherLicenseUrl}', '{otherPermissionUrl}'";
                }
            }
            else if (!string.IsNullOrEmpty(otherLicenseUrl))
            {
                meta.OtherLicenseUrl = otherLicenseUrl;
            }
            else if (!string.IsNullOrEmpty(otherPermissionUrl))
            {
                // otherPermissionUrl => otherLicenseUrl
                meta.OtherLicenseUrl = otherPermissionUrl;
            }
            else
            {
                // null
            }

            return meta;
        }

        public static string GetLicenseUrl(JsonNode vrm0)
        {
            string l0 = default;
            string l1 = default;
            foreach (var kv in vrm0.ObjectItems())
            {
                switch (kv.Key.GetString())
                {
                    case "otherLicenseUrl":
                        l0 = kv.Value.GetString();
                        break;

                    case "otherPermissionUrl":
                        l1 = kv.Value.GetString();
                        break;
                }
            }
            if (!string.IsNullOrWhiteSpace(l0))
            {
                return l0;
            }
            if (!string.IsNullOrWhiteSpace(l1))
            {
                return l1;
            }
            return "";
        }

        static bool IsSingleList(string key, string lhs, List<string> rhs)
        {
            if (rhs.Count != 1) throw new MigrationException(key, $"{rhs.Count}");
            return lhs == rhs[0];
        }

        static string AvatarPermission(string key, UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType x)
        {
            switch (x)
            {
                case UniGLTF.Extensions.VRMC_vrm.AvatarPermissionType.everyone: return "Everyone";
                    // case AvatarPermissionType.onlyAuthor: return "OnlyAuthor";
                    // case AvatarPermissionType.explicitlyLicensedPerson: return "Explicited";
            }
            throw new MigrationException(key, $"{x}");
        }

        public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.Meta vrm1)
        {
            if (vrm0["title"].GetString() != vrm1.Name) throw new MigrationException("meta.title", vrm1.Name);
            if (vrm0["version"].GetString() != vrm1.Version) throw new MigrationException("meta.version", vrm1.Version);
            if (!IsSingleList("meta.author", vrm0["author"].GetString(), vrm1.Authors)) throw new MigrationException("meta.author", $"{vrm1.Authors}");
            if (vrm0["contactInformation"].GetString() != vrm1.ContactInformation) throw new MigrationException("meta.contactInformation", vrm1.ContactInformation);
            if (!IsSingleList("meta.reference", vrm0["reference"].GetString(), vrm1.References)) throw new MigrationException("meta.reference", $"{vrm1.References}");
            if (vrm0["texture"].GetInt32() != vrm1.ThumbnailImage) throw new MigrationException("meta.texture", $"{vrm1.ThumbnailImage}");

            if (vrm0["allowedUserName"].GetString() != AvatarPermission("meta.allowedUserName", vrm1.AvatarPermission)) throw new MigrationException("meta.allowedUserName", $"{vrm1.AvatarPermission}");
            if (vrm0["violentUssageName"].GetString() == "Allow" != vrm1.AllowExcessivelyViolentUsage) throw new MigrationException("meta.violentUssageName", $"{vrm1.AllowExcessivelyViolentUsage}");
            if (vrm0["sexualUssageName"].GetString() == "Allow" != vrm1.AllowExcessivelySexualUsage) throw new MigrationException("meta.sexualUssageName", $"{vrm1.AllowExcessivelyViolentUsage}");

            if (vrm0["commercialUssageName"].GetString() == "Allow")
            {
                if (vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalNonProfit)
                {
                    throw new MigrationException("meta.commercialUssageName", $"{vrm1.CommercialUsage}");
                }
            }
            else
            {
                if (vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.corporation
                || vrm1.CommercialUsage == UniGLTF.Extensions.VRMC_vrm.CommercialUsageType.personalProfit)
                {
                    throw new MigrationException("meta.commercialUssageName", $"{vrm1.CommercialUsage}");
                }
            }

            if (MigrationVrmMeta.GetLicenseUrl(vrm0) != vrm1.OtherLicenseUrl) throw new MigrationException("meta.otherLicenseUrl", vrm1.OtherLicenseUrl);

            switch (vrm0["licenseName"].GetString())
            {
                case "Other":
                    {
                        if (vrm1.Modification != UniGLTF.Extensions.VRMC_vrm.ModificationType.prohibited) throw new MigrationException("meta.licenceName", $"{vrm1.Modification}");
                        if (vrm1.AllowRedistribution.Value) throw new MigrationException("meta.liceneName", $"{vrm1.Modification}");
                        break;
                    }

                default:
                    throw new NotImplementedException();
            }
        }
    }
}
