namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;

    using Dapper;

    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;

    using Shared.EntityModels;

    /// <inheritdoc />
    public class CompanyServices : ICompanyService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <summary>
        /// Initializes a new instance of the <see cref="CompanyServices"/> class.
        /// </summary>
        /// <param name="unitOfWork">
        /// The unit of work.
        /// </param>
        public CompanyServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc/>
        public async Task<int> InsertCompanyAsync(CompanyModel model)
        {
            var checkIfQuery = $@"Select count(*) from ""Company"" where lower(""Name"") = '{model.Name.ToLower()}' and ""TypeOf"" = '{model.TypeOf}'";
            var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
            if (checkIf > 0)
            {
                return -1;
            }

            var company = new Company
            {
                CreatedDate = DateTime.Now,
                Location = model.Location,
                Name = model.Name,
                TypeOf = model.TypeOf,
                CreatedBy = model.CreatedBy
            };
            return await this.unitOfWork.Company.InsertAsync(company);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<CompanyFilterModel>> FetchAllAsync(CompanyFilterModel model)
        {
            var where = "where 1=1";
            if (model.FromDate != null)
            {
                where += $@" AND C.""CreatedDate""::DATE >= '{model.FromDate}'::timestamp without time zone ";
            }
            if (model.ToDate != null)
            {
                where += $@" AND C.""CreatedDate""::DATE <= '{model.ToDate}'::timestamp without time zone ";
            }
            if (model.CreatedBy != null)
            {
                where += $@" and C.""CreatedBy""={model.CreatedBy}";
            }
            if (model.Location != null)
            {
                where += $@" and L.""LookupValueId""='{model.Location}'";
            }
            if (!string.IsNullOrEmpty(model.TypeOf))
            {
                where += $@" and C.""TypeOf"" = '{model.TypeOf}'";
            }

            if (model.CompanyId != null)
            {
                where += $@" and C.""CompanyId"" ={model.CompanyId}";
            }
            if (!string.IsNullOrEmpty(model.Location))
            {
                where += $@" and C.""Location"" ilike %'{model.Location}'%";
            }

            if (!string.IsNullOrEmpty(model.Name))
            {
                where += $@" and lower(C.""Name"") ilike '%{model.Name.ToLower()}%' ";
            }

            var query = $@"SELECT C.*
                                 , A.""FullName"" as ""CreatedByName"",M.""FullName"" as ""ModifiedByName""
                        FROM ""Company"" C
                       left join ""Account"" A on A.""AccountId"" = C.""CreatedBy""
                       left join ""Account"" M on M.""AccountId"" = C.""ModifiedBy""
                        {where} order by C.""CreatedDate"" desc ";
            return await this.unitOfWork.Current.QueryAsync<CompanyFilterModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateCompanyAsync(CompanyModel model)
        {
            var checkIfQuery = $@"Select count(*) from ""Company"" where lower(""Name"") = '{model.Name.ToLower()}' and ""TypeOf"" = '{model.TypeOf}' and ""CompanyId"" <> {model.CompanyId}";
            var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
            if (checkIf > 0)
            {
                return -1;
            }

            var record = await this.unitOfWork.Company.FindAsync(m => m.CompanyId == model.CompanyId);
            record.Name = model.Name;
            record.Location = model.Location;
            record.ModifiedBy = model.ModifiedBy;
            record.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            return await this.unitOfWork.Company.UpdateAsync(record);
        }

        /// <inheritdoc/>
        public async Task<int> DeleteCompanyAsync(int companyId)
        {
            var query = $@"Delete FROM ""Company"" where ""CompanyId"" = {companyId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<CompanyModel> FetchAsync(CompanyModel model)
        {
            var where = "where 1=1";
            if (!string.IsNullOrEmpty(model.TypeOf))
            {
                where += $@" and ""TypeOf"" = '{model.TypeOf}'";
            }

            if (!string.IsNullOrEmpty(model.Name))
            {
                where += $@" and LOWER(""Name"") = '{model.Name.Replace("'", "''").ToLower()}'";
            }

            var query = $@"SELECT * FROM ""Company"" {where} order by ""CreatedDate"" desc limit 1";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<CompanyModel>(query);
        }
    }
}