using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using OnlineAssessment.Common;
using OnlineAssessment.Domain;

namespace OnlineAssessment.Data.EFCore
{
    public abstract class EfCoreRepository<TEntity, TContext> : IRepository<TEntity>
        where TEntity : class, IEntity
        where TContext : DbContext
    {
        private readonly TContext context;
        private readonly ResponseMessage responseMessage;
        public EfCoreRepository(TContext context)
        {
            this.context = context;
        }

        public EfCoreRepository(TContext context, IOptionsSnapshot<ResponseMessage> responseMessage)
        {
            this.context = context;
            this.responseMessage = responseMessage.Value;
        }

        /// <summary>
        /// Get all records
        /// </summary>
        /// <returns></returns>
        public virtual List<TEntity> GetAll()
        {
            return (context.Set<TEntity>().ToList<TEntity>());
        }

        /// <summary>
        /// Get a single record by id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> Get(int id)
        {
            return await context.Set<TEntity>().FindAsync(id);
        }

        /// <summary>
        /// Add a new record
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> Add(TEntity entity)
        {
            context.Set<TEntity>().Add(entity);
            await context.SaveChangesAsync();
            return entity;
        }

        /// <summary>
        /// Edit and update an existing record
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public Task<TEntity> Update(TEntity entity)
        {
            try
            {
                context.Entry(entity).State = EntityState.Modified;
                context.SaveChanges();
            }
            catch (Exception ex)
            {
                throw (ex);
            }
            return entity as Task<TEntity>;
        }

        /// <summary>
        /// Delete a record
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Delete(int id)
        {
            dynamic entity = context.Set<TEntity>().Find(id);
            if (entity == null)
            {
                return false;
            }
            context.Entry(entity).State = EntityState.Modified;
            entity.IsActive = false;
            context.SaveChanges();

            return true;
        }

        public string GetMessageByCode(string message_code, string word2replace = "")
        {
            string theMessage = string.Empty;
            try
            {
                if (string.IsNullOrWhiteSpace(word2replace))
                {
                    theMessage = responseMessage.Values[message_code].ToString();
                }
                else
                {
                    theMessage = string.Format(responseMessage.Values[message_code].ToString(), word2replace);
                }
            }
            catch (Exception ex)
            {
                theMessage = ex.Message.ToString();
            }
            return theMessage;
        }

        public byte[] ConvertStringToBytes(string theString) => Encoding.ASCII.GetBytes(theString);

        public string ConvertBytesToString(byte[] theBytes) => Encoding.ASCII.GetString(theBytes);
    }
}
