using System.Reflection;
using MTWorkHR.Core.UnitOfWork;
using MTWorkHR.Infrastructure.DBContext;
using MTWorkHR.Core.IRepositories;
using MTWorkHR.Core.Global;
using MTWorkHR.Infrastructure.Repositories;
using MTWorkHR.Core.IRepositories.Base;
using MTWorkHR.Infrastructure.Entities;

namespace MTWorkHR.Infrastructure.UnitOfWorks
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly HRDataContext context;

        public IPermissionRepository Permission { get; }
        public ICompanyRepository Company { get; }
        public IUserTaskRepository UserTask { get; }
        public ITaskStatusRepository UserTaskStatus { get; }
        public IUserTaskHistoryRepository UserTaskHistory { get; }
        public IUserTaskAttachmentRepository UserTaskAttachment { get; }

        public IProjectRepository Project { get; }
        public IProjectTeamRepository ProjectTeam { get; }
        public ITeamRepository Team{ get; }
        public ITeamUserRepository TeamUser { get; }
        public IMeetingRepository Meeting{ get; }
        public IMeetingUserRepository MeetingUser { get; }
        public IAttendanceRepository Attendance { get; }
        public IOrderTypeRepository OrderType { get; }
        public ILeaveTypeRepository LeaveType { get; }
        public IOrderAllocationRepository OrderAllocation { get; }
        public IOrderRequestRepository OrderRequest { get; }
        public ICountryLookupRepository CountryLookup { get; }
        public IIndustryRepository Industry { get; }
        public IJobTitleRepository JobTitle { get; }
        public IQualificationRepository Qualification { get; }
        public IUniversityRepository University { get; }
        public ILoginOTPRepository LoginOTP { get; }
        public ICityRepository City { get; }
        public IChatMessageRepository ChatMessage { get; }
        public IHubConnectionRepository HubConnection { get; }
        public IContractRepository Contract{ get; }
        public IContractTaskAttachmentRepository ContractTaskAttachment { get; }
        public IProjectStageAttachmentRepository ProjectStageAttachment { get; }
        public ISubscriptionConfigurationRepository SubscriptionConfiguration { get; }
        public IInvoiceRepository Invoice { get; }
        public IJobInterviewRepository JobInterview { get; }
        
        public UnitOfWork(HRDataContext _context
            , IPermissionRepository permission
            , ICompanyRepository company
            , IUserTaskRepository userTask
            , IProjectRepository project
            , IUserTaskHistoryRepository projectHistory
            , ITaskStatusRepository userTaskStatus
            , IUserTaskAttachmentRepository userTaskAttachment
            , ITeamRepository teamRepository
            , IMeetingRepository meetingRepository
            , IAttendanceRepository attendance
            , IOrderRequestRepository orderRequest
            , IOrderAllocationRepository orderAllocation
            , IOrderTypeRepository orderType
            , ILeaveTypeRepository leaveType
            , ICountryLookupRepository countryLookup
            , IIndustryRepository industry
            , IJobTitleRepository jobTitle
            , IQualificationRepository qualification
            , IUniversityRepository university
            , ILoginOTPRepository loginOTP
            , ICityRepository city
            , ITeamUserRepository teamUser
            , IMeetingUserRepository meetingUser
            , IProjectTeamRepository projectTeam
            , IChatMessageRepository chatMessage
            , IContractRepository contract
            , IContractTaskAttachmentRepository contractTaskAttachment
            , IProjectStageAttachmentRepository projectStageAttachment
            , IHubConnectionRepository connection
            , ISubscriptionConfigurationRepository subscriptionConfiguration
            , IInvoiceRepository invoice
            , IJobInterviewRepository jobInterview
            )
        {
            context = _context;
            this.Permission = permission;
            this.Company = company;
            this.UserTask = userTask;
            this.Project = project;
            this.UserTaskHistory = projectHistory;
            this.UserTaskStatus = userTaskStatus;
            this.UserTaskAttachment = userTaskAttachment;
            this.Team = teamRepository;
            this.Meeting = meetingRepository;
            this.Attendance = attendance;
            this.OrderType = orderType;
            this.OrderRequest = orderRequest;
            this.OrderAllocation = orderAllocation;
            this.LeaveType = leaveType;
            this.CountryLookup = countryLookup;
            this.Industry = industry;
            this.JobTitle = jobTitle;
            this.Qualification = qualification;
            this.University = university;
            LoginOTP = loginOTP;
            City = city;
            TeamUser = teamUser;
            MeetingUser = meetingUser;
            ProjectTeam = projectTeam;
            ChatMessage = chatMessage;
            Contract = contract;
            HubConnection = connection;
            ContractTaskAttachment = contractTaskAttachment;
            ProjectStageAttachment = projectStageAttachment;
            SubscriptionConfiguration = subscriptionConfiguration;
            Invoice = invoice;
            JobInterview = jobInterview;
        }

        public async Task<int> CompleteAsync()
        {
            try
            {
                return await context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                RollbackTran();
                throw ex;
            }

        }

        public object GetRepositoryByName(string name)
        {
            Type type = this.GetType();
            PropertyInfo info = type.GetProperty(name);
            if (info == null)
                throw new AppException(ExceptionEnum.PropertyNotAccess, name, type.FullName);
            //type.FullName, String.Format("A property called {0} can't be accessed for type {1}.", name));

            return info.GetValue(this, null);
        }

        public void BeginTran()
        {
            context.Database.BeginTransaction();
        }

        public void CommitTran()
        {
            context.Database.CommitTransaction();
        }

        public void RollbackTran()
        {
            var transaction = context.Database.CurrentTransaction;
            if (transaction != null)
                context.Database.RollbackTransaction();
        }
    }
}
