using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using nft.framework.repository;
using nft.framework;
using static System.Diagnostics.Trace;
using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using System.Collections.Generic;
using System.Linq;
using nft.framework;

namespace TestCoreProject.core
{

    [TestClass]
    public class RepositoryBaseTest
    {
        private TestRepository repository;

        [TestMethod]
        public void RepositoryBase()
        {
            this.repository = new TestRepository();
            WriteLine("TestRepository created.");

            AreEqual(repository.Count, 0, "最初はCount=0");

            TestId id0 = new TestId("999");
            TestData data0 = new TestData(id0, $"#{id0}");

            repository.Add(data0);
            AreEqual(repository.Count, 1, "追加したのでCount=1");
            AreEqual(repository[id0], data0, "ID=999で登録したオブジェクトが取得できること");
            AreEqual(repository[new TestId("000")], null, "存在しないID=000でnullが取得できること");
            AreEqual(repository.RemoveByID(new TestId("000")), null, "存在しないID=000で削除してもエラーにならずnullが返却されること");

            List<IHasNameAndID> list = repository.List.ToList<IHasNameAndID>();
            CollectionAssert.AreEqual(list, new List<IHasNameAndID> { data0 });

            TestData removed = repository.RemoveByID(id0);
            AreEqual(repository.Count, 0, "削除したのでCount=0");
            AreEqual(removed, data0, "ID=999で登録したオブジェクトが削除されていること");

            WriteLine("複数要素追加のテスト");
            Dictionary<TestId, IHasNameAndID> savedData = new Dictionary<TestId, IHasNameAndID>();
            TestData data;
            for (int i = 1; i < 10; i++)
            { // 1～9まで追加していき、数とリストの中身が正しいことを確認
                TestId id = new TestId($"{i}");
                data = new TestData(id, $"#{id}");
                savedData.Add(id, data);
                repository.Add(data);
                AreEqual(repository.Count, savedData.Count);
                CollectionAssert.AreEqual(repository.List.ToList<IHasNameAndID>(), savedData.Values);
            }
            for (int i = 1; i < 10; i++)
            { // 一部のデータを削除しつつ、idとの紐付けが正しいことを確認
                TestId id = new TestId($"{i}");
                switch (i % 3)
                { // ３パターンを試す
                    case 0: // 何もせず比較
                        AreEqual(repository[id], savedData[id]);
                        break;
                    case 1: // 比較して削除
                        AreEqual(repository[id], savedData[id]);
                        data = repository.RemoveByID(id);
                        AreEqual(data, savedData[id]);
                        AreEqual(repository[id], null);
                        break;
                    case 2:　// 削除後に比較
                        data = repository.RemoveByID(id);
                        AreEqual(data, savedData[id]);
                        AreEqual(repository[id], null);
                        break;
                }
            }
            this.repository = null;
        }

        [TestMethod]
        public void IRepositoryExtension()
        {
            this.repository = new TestRepository();
            WriteLine("IModelRepository拡張メソッドのテスト");
            Dictionary<TestId, TestData> savedData = new Dictionary<TestId, TestData>();
            TestData data;
            for (int i = 1; i < 10; i++)
            { // 1～9まで追加していき、数とリストの中身が正しいことを確認
                TestId id = new TestId($"{i}");
                data = new TestData(id, $"#{id}");
                savedData.Add(id, data);
                repository.Add(data);
                CollectionAssert.AreEqual(repository.List.ToList<IHasNameAndID>(), savedData.Values);
            }
            TestData _default = new TestData(new TestId("default"), "default");
            // 拡張メソッド findByID, hasID, removeByID
            for (int i = 1; i < 10; i++)
            { // 一部のデータを削除しつつ、idとの紐付けが正しいことを確認
                TestId id = new TestId($"{i}");
                switch (i % 3)
                {
                    case 0: // 何もせず比較
                        AreEqual(repository.findByID(id, _default), savedData[id]);
                        break;
                    default: // 比較して削除
                        AreEqual(repository.findByID(id, _default), savedData[id]);
                        repository.Remove(savedData[id]);
                        AreEqual(repository.findByID(id, _default), _default);
                        break;
                }
            }
            this.repository = null;
        }
    }

    class TestId : VAbstractIdentifier
    {
        public TestId(string idStr) : base(idStr) {}
    }

    class TestData : IHasNameAndID
    {
        private readonly TestId id;
        private readonly string name;
        public IIdentifier ID { get { return id; } }
        public string Name { get { return name; } }
        public TestData(TestId id, string name)
        {
            this.id = id;
            this.name = name;
        }
    }

    class TestRepository : RepositoryBase<TestId,TestData>
    {
        
    }
}
