using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using UnivateProperties_API.Containers.Property;
using UnivateProperties_API.Context;
using UnivateProperties_API.Model.Properties;

namespace UnivateProperties_API.Repository.Properties
{
    public class UserDefinedGroupRepository : IUserDefinedGroupRepository
    {
        private readonly DataContext dBContext;

        public UserDefinedGroupRepository(DataContext _dBContext)
        {
            dBContext = _dBContext;
        }

        public List<UserDefinedGroup> Get(Func<UserDefinedGroup, bool> where)
        {
            return dBContext.UserDefinedGroups.Where(where).OrderBy(x => x.Rank).ToList();
        }

        public List<UserDefinedGroup> GetAll()
        {
            return dBContext.UserDefinedGroups.OrderBy(x => x.Rank).ToList();
        }

        public UserDefinedGroup GetDetailed(Func<UserDefinedGroup, bool> first)
        {
            return dBContext.UserDefinedGroups.FirstOrDefault(first);
        }

        public List<UserDefinedGroup> GetDetailedAll()
        {
            return dBContext.UserDefinedGroups.ToList();
        }

        public List<Group> GetFieldList(string name)
        {
            List<Group> FieldGroups = new List<Group>();
            List<UserDefinedGroup> Groups;
            if (name == "Property Overview")
                Groups = dBContext.UserDefinedGroups.Where(x => x.Description == "Property Overview").OrderBy(x => x.Rank).ToList();
            else
                Groups = dBContext.UserDefinedGroups.Where(x => x.Description != "Property Overview").OrderBy(x => x.Rank).ToList();


            foreach (var group in Groups)
            {
                var fields = dBContext.UserDefinedFields.Where(x => x.GroupId == group.Id).ToList();
                if (fields.Count > 0)
                {
                    var item = new Group()
                    {
                        Name = group.Description,
                        Fields = new List<GroupFields>()
                    };

                    FieldGroups.Add(item);

                    foreach (var field in fields)
                    {
                        item.Fields.Add(new GroupFields()
                        {
                            ID = field.Id,
                            Name = field.FieldName,
                            Type = field.FieldType
                        });
                    }
                }
            }

            return FieldGroups;
        }

        public List<Group> GetFieldList(string propertyType, string name, int propertyID)
        {
            List<Group> FieldGroups = GetFieldList(name);
            if (name == "Property Overview")
                FieldGroups = GetFieldList(name);
            else
                FieldGroups = GetFieldListByPropType(propertyType);

            var savedValues = dBContext.PropertyUserFields.Where(x => x.PropertyId == propertyID).ToList();
            foreach (Group group in FieldGroups)
            {
                foreach(GroupFields field in group.Fields)
                {
                    var item = savedValues.Find(x => x.UserDefinedFieldId == field.ID);
                    if (item != null)
                    {
                        field.Value = item.Value ?? "";
                        field.ItemID = item.Id;
                    }
                }
            }

            return FieldGroups;
        }

        public List<Group> GetFieldListByPropType(string propertyType)
        {
            List<Group> FieldGroups = new List<Group>();
            List<UserDefinedGroup> Groups;
            PropertyUsageType usageType = PropertyUsageType.Both;
            switch (propertyType.ToUpper())
            {
                case "RESIDENTIAL":
                    usageType = PropertyUsageType.Residential;
                    break;
                case "COMMERCIAL":
                    usageType = PropertyUsageType.Commercial;
                    break;
            }

            Groups = dBContext.UserDefinedGroups.Where(x => (x.UsageType == usageType || x.UsageType == PropertyUsageType.Both) && x.Description != "Property Overview").OrderBy(x => x.Rank).ToList();

            foreach (var group in Groups)
            {
                var fields = dBContext.UserDefinedFields.Where(x => x.GroupId == group.Id).ToList();
                if (fields.Count > 0)
                {
                    var item = new Group()
                    {
                        Name = group.Description,
                        Fields = new List<GroupFields>()
                    };

                    FieldGroups.Add(item);

                    foreach (var field in fields)
                    {
                        item.Fields.Add(new GroupFields()
                        {
                            ID = field.Id,
                            Name = field.FieldName,
                            Type = field.FieldType
                        });
                    }
                }
            }

            return FieldGroups;
        }

        public void Insert(UserDefinedGroup item)
        {
            dBContext.UserDefinedGroups.Add(item);
            Save();
        }

        public void Insert(IEnumerable<UserDefinedGroup> items)
        {
            foreach (var item in items)
            {
                dBContext.UserDefinedGroups.Add(item);
                Save();
            }
        }

        public void Remove(UserDefinedGroup item)
        {
            dBContext.UserDefinedGroups.Remove(item);
            Save();
        }

        public void Remove(IEnumerable<UserDefinedGroup> items)
        {
            foreach (var item in items)
            {
                dBContext.UserDefinedGroups.Remove(item);
                Save();
            }
        }

        public void RemoveAtId(int item)
        {
            var userDefinedGroups = Get(x => x.Id == item).FirstOrDefault();
            if (userDefinedGroups != null)
            {
                dBContext.UserDefinedGroups.Remove(userDefinedGroups);
                Save();
            }
        }

        public void Save()
        {
            dBContext.SaveChanges();
        }

        public void Update(UserDefinedGroup item)
        {
            dBContext.Entry(item).State = EntityState.Modified;
            Save();
        }

        public int NewId()
        {
            // Not sure if properties need it
            return 0;
        }
    }
}