// Copyright Naked Objects Group Ltd, 45 Station Road, Henley on Thames, UK, RG9 1AT
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
// Unless required by applicable law or agreed to 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.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NakedFramework.Architecture.Component;
using NakedFramework.Architecture.Facet;
using NakedFramework.Architecture.Reflect;
using NakedFramework.Architecture.SpecImmutable;
using NakedObjects.Reflector.FacetFactory;

// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMember.Local

namespace NakedObjects.Reflector.Test.FacetFactory;

[TestClass]
public class FindMenuFacetFactoryTest : AbstractFacetFactoryTest {
    private FindMenuFacetFactory facetFactory;

    protected override Type[] SupportedTypes => new[] { typeof(IFindMenuFacet) };

    protected override IFacetFactory FacetFactory => facetFactory;

    [TestMethod]
    public void TestFindMenuFacetNotAddedToParameterByDefault() {
        IImmutableDictionary<string, ITypeSpecBuilder> metamodel = new Dictionary<string, ITypeSpecBuilder>().ToImmutableDictionary();

        var method = FindMethod(typeof(Customer), "Action1", new[] { typeof(Foo), typeof(Foo) });
        metamodel = facetFactory.ProcessParams(Reflector, method, 0, Specification, metamodel);
        var facet = Specification.GetFacet(typeof(IFindMenuFacet));
        Assert.IsNull(facet);
        Assert.IsNotNull(metamodel);
    }

    [TestMethod]
    public void TestFindMenuAnnotationOnParameterPickedUp() {
        IImmutableDictionary<string, ITypeSpecBuilder> metamodel = new Dictionary<string, ITypeSpecBuilder>().ToImmutableDictionary();

        var method = FindMethod(typeof(Customer), "Action1", new[] { typeof(Foo), typeof(Foo) });
        metamodel = facetFactory.ProcessParams(Reflector, method, 1, Specification, metamodel);
        Assert.IsNotNull(Specification.GetFacet(typeof(IFindMenuFacet)));
        Assert.IsNotNull(metamodel);
    }

    [TestMethod]
    public void TestFindMenuAnnotationIgnoredForPrimitiveParameter() {
        IImmutableDictionary<string, ITypeSpecBuilder> metamodel = new Dictionary<string, ITypeSpecBuilder>().ToImmutableDictionary();

        var method = FindMethod(typeof(Customer), "Action2", new[] { typeof(string) });
        metamodel = facetFactory.ProcessParams(Reflector, method, 0, Specification, metamodel);
        Assert.IsNull(Specification.GetFacet(typeof(IFindMenuFacet)));
        Assert.IsNotNull(metamodel);
    }

    [TestMethod]
    public void TestFindMenuFacetNotAddedToPropertyByDefault() {
        IImmutableDictionary<string, ITypeSpecBuilder> metamodel = new Dictionary<string, ITypeSpecBuilder>().ToImmutableDictionary();

        var property = FindProperty(typeof(Customer), "Property1");
        metamodel = facetFactory.Process(Reflector, property, MethodRemover, Specification, metamodel);
        Assert.IsNull(Specification.GetFacet(typeof(IFindMenuFacet)));
        Assert.IsNotNull(metamodel);
    }

    [TestMethod]
    public void TestFindMenuAnnotationOnPropertyPickedUp() {
        IImmutableDictionary<string, ITypeSpecBuilder> metamodel = new Dictionary<string, ITypeSpecBuilder>().ToImmutableDictionary();

        var property = FindProperty(typeof(Customer), "Property2");
        metamodel = facetFactory.Process(Reflector, property, MethodRemover, Specification, metamodel);
        Assert.IsNotNull(Specification.GetFacet(typeof(IFindMenuFacet)));
        Assert.IsNotNull(metamodel);
    }

    [TestMethod]
    public void TestFindMenuAnnotationIgnoredForPrimitiveProperty() {
        IImmutableDictionary<string, ITypeSpecBuilder> metamodel = new Dictionary<string, ITypeSpecBuilder>().ToImmutableDictionary();

        var property = FindProperty(typeof(Customer), "Property3");
        metamodel = facetFactory.Process(Reflector, property, MethodRemover, Specification, metamodel);
        Assert.IsNull(Specification.GetFacet(typeof(IFindMenuFacet)));
        Assert.IsNotNull(metamodel);
    }

    [TestMethod]
    public override void TestFeatureTypes() {
        var featureTypes = facetFactory.FeatureTypes;
        Assert.IsFalse(featureTypes.HasFlag(FeatureType.Objects));
        Assert.IsTrue(featureTypes.HasFlag(FeatureType.Properties));
        Assert.IsFalse(featureTypes.HasFlag(FeatureType.Collections));
        Assert.IsFalse(featureTypes.HasFlag(FeatureType.Actions));
        Assert.IsTrue(featureTypes.HasFlag(FeatureType.ActionParameters));
    }

    #region Nested type: Customer

    private class Customer {
        public Foo Property1 { get; set; }

        [FindMenu]
        public Foo Property2 { get; set; }

        [FindMenu]
        public string Property3 { get; set; }

        public void Action1(Foo param1, [FindMenu] Foo param2) { }

        public void Action2([FindMenu] string param1) { }
    }

    #endregion

    #region Nested type: Foo

    private class Foo { }

    #endregion

    #region Setup/Teardown

    [TestInitialize]
    public override void SetUp() {
        base.SetUp();
        facetFactory = new FindMenuFacetFactory(GetOrder<FindMenuFacetFactory>(), LoggerFactory);
    }

    [TestCleanup]
    public override void TearDown() {
        facetFactory = null;
        base.TearDown();
    }

    #endregion
}

// Copyright (c) Naked Objects Group Ltd.