// ==========================================================================
//  Squidex Headless CMS
// ==========================================================================
//  Copyright (c) Squidex UG (haftungsbeschraenkt)
//  All rights reserved. Licensed under the MIT license.
// ==========================================================================

using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;

namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
{
    public static class GuardSchemaField
    {
        public static void CanAdd(AddField command, Schema schema)
        {
            Guard.NotNull(command);

            Validate.It(e =>
            {
                if (!command.Name.IsPropertyName())
                {
                    e(Not.ValidJavascriptName(nameof(command.Name)), nameof(command.Name));
                }

                if (command.Properties == null)
                {
                    e(Not.Defined(nameof(command.Properties)), nameof(command.Properties));
                }
                else
                {
                    var errors = FieldPropertiesValidator.Validate(command.Properties);

                    errors.Foreach((x, _) => x.WithPrefix(nameof(command.Properties)).AddTo(e));
                }

                if (command.ParentFieldId != null)
                {
                    var arrayField = GuardHelper.GetArrayFieldOrThrow(schema, command.ParentFieldId.Value, false);

                    if (arrayField.FieldsByName.ContainsKey(command.Name))
                    {
                        e(T.Get("schemas.fieldNameAlreadyExists"));
                    }
                }
                else
                {
                    if (command.ParentFieldId == null && !command.Partitioning.IsValidPartitioning())
                    {
                        e(Not.Valid("Partitioning"), nameof(command.Partitioning));
                    }

                    if (schema.FieldsByName.ContainsKey(command.Name))
                    {
                        e(T.Get("schemas.fieldNameAlreadyExists"));
                    }
                }
            });
        }

        public static void CanUpdate(UpdateField command, Schema schema)
        {
            Guard.NotNull(command);

            GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, false);

            Validate.It(e =>
            {
                if (command.Properties == null)
                {
                    e(Not.Defined("Properties"), nameof(command.Properties));
                }
                else
                {
                    var errors = FieldPropertiesValidator.Validate(command.Properties);

                    errors.Foreach((x, _) => x.WithPrefix(nameof(command.Properties)).AddTo(e));
                }
            });
        }

        public static void CanHide(HideField command, Schema schema)
        {
            Guard.NotNull(command);

            var field = GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, false);

            if (!field.IsForApi(true))
            {
                throw new DomainException(T.Get("schemas.uiFieldCannotBeHidden"));
            }
        }

        public static void CanDisable(DisableField command, Schema schema)
        {
            Guard.NotNull(command);

            var field = GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, false);

            if (!field.IsForApi(true))
            {
                throw new DomainException(T.Get("schemas.uiFieldCannotBeDisabled"));
            }
        }

        public static void CanShow(ShowField command, Schema schema)
        {
            Guard.NotNull(command);

            var field = GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, false);

            if (!field.IsForApi(true))
            {
                throw new DomainException(T.Get("schemas.uiFieldCannotBeShown"));
            }
        }

        public static void CanEnable(EnableField command, Schema schema)
        {
            Guard.NotNull(command);

            var field = GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, false);

            if (!field.IsForApi(true))
            {
                throw new DomainException(T.Get("schemas.uiFieldCannotBeEnabled"));
            }
        }

        public static void CanDelete(DeleteField command, Schema schema)
        {
            Guard.NotNull(command);

            GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, false);
        }

        public static void CanLock(LockField command, Schema schema)
        {
            Guard.NotNull(command);

            GuardHelper.GetFieldOrThrow(schema, command.FieldId, command.ParentFieldId, true);
        }
    }
}
