﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Starcounter;
using Starcounter.Linq;

namespace People
{
    static class Indexes
    {
        public static void Ensure()
        {
            Ensure(
                (Person o) => o.LastName, SortOrder.Asc,
                (Person o) => o.FirstName, SortOrder.Asc
            );
            Ensure((Address o) => o.Owner);
            Ensure((EmailAddress o) => o.Owner);
            Ensure((PhoneNumber o) => o.Owner);
        }

        #region Implementation

        public enum SortOrder
        {
            Asc,
            Desc
        }

        public enum Uniqueness
        {
            Unique,
            NotUnique
        }

        private static void Ensure<Class, Property1>(Expression<Func<Class, Property1>> selector1, SortOrder sortOrder1 = SortOrder.Asc, Uniqueness unique = Uniqueness.NotUnique)
        {
            Ensure(typeof(Class).FullName, new[] { Tuple.Create(ExtractName(selector1), sortOrder1) }, unique);
        }

        private static void Ensure<Class, Property1, Property2>(Expression<Func<Class, Property1>> selector1, SortOrder sortOrder1, Expression<Func<Class, Property2>> selector2, SortOrder sortOrder2, Uniqueness unique = Uniqueness.NotUnique)
        {
            Ensure(typeof(Class).FullName, new[] {
                Tuple.Create(ExtractName(selector1), sortOrder1),
                Tuple.Create(ExtractName(selector2), sortOrder2),
            }, unique);
        }

        private static void Ensure(string typeName, IReadOnlyCollection<Tuple<string, SortOrder>> properties, Uniqueness unique)
        {
            string[] typeNameParts = typeName.Split('.');
            string quotedTypeName = string.Join(".", typeNameParts.Select(o => $@"""{o}"""));
            string indexName = $"{string.Join("_", typeNameParts)}__{(unique == Uniqueness.Unique ? "UNIQUE__" : "")}_{string.Join("_", properties.Select(o => $"{o.Item1}_{o.Item2}"))}";

            if (!DbLinq.Objects<Starcounter.Metadata.Index>().Any(x => x.Name == indexName))
            {
                Db.SlowSQL($"CREATE {(unique == Uniqueness.Unique ? "UNIQUE " : "")}INDEX {indexName} ON {quotedTypeName}({string.Join(", ", properties.Select(o => $@"""{o.Item1}"" {o.Item2}"))})");
            }
        }

        private static string ExtractName<Class, Property>(Expression<Func<Class, Property>> selector)
        {
            var memberExpr = (MemberExpression)selector.Body;
            return memberExpr.Member.Name;
        }

        #endregion
    }
}