namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Configurations;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Shared.EntityModels;
    using Shared.UserModels;
    using Shared.UserModels.Filters;

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

        /// <summary>
        /// The amazon s 3 configuration.
        /// </summary>
        private readonly IAmazonS3Configuration amazonS3Configuration;

        private readonly IRunningEnvironment runningEnvironment;

        ///// <summary>
        ///// The ftp configuration.
        ///// </summary>
        //private readonly IFtpConfiguration ftpConfiguration;

        ///// <summary>
        ///// The ftp configuration.
        ///// </summary>
        //private readonly INewFtpConfiguration newftpConfiguration;

        /// <inheritdoc cref="IPatientDocumentService" />
        public PatientDocumentServices(IUnitOfWork unitOfWork, IAmazonS3Configuration amazonS3Configuration,
            IRunningEnvironment runningEnvironment
            //IFtpConfiguration FtpConfiguration, INewFtpConfiguration NewftpConfiguration
            )
        {
            this.unitOfWork = unitOfWork;
            this.amazonS3Configuration = amazonS3Configuration;
            this.runningEnvironment = runningEnvironment;
            //this.ftpConfiguration = FtpConfiguration;
            //this.newftpConfiguration = NewftpConfiguration;
        }

        /// <inheritdoc />
        public Task<IEnumerable<PatientDocumentModel>> FetchAsync(PatientDocumentFilterModel model)
        {
            var where = string.Empty;

            if (model.PatientId != 0)
            {
                where = $@" WHERE prd.""Active"" IS TRUE AND prd.""PatientId"" = {model.PatientId}";
            }

            if (model.PatientDocumentId != null)
            {
                where = $@" and prd.""PatientDocumentId"" = {model.PatientDocumentId}";
            }

            //var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", prd.""PatientId"", prd.""PatientDocumentId"", prd.""DocumentType"", prd.""DocumentName"", CASE WHEN prd.""Description"" IS NULL THEN '' ELSE prd.""Description"" END ""Description"", prd.""ContentType"", prd.""Size"",prd.""IsRead"",
            //                    prd.""UploadedDate"", prd.""UploadedBy"", act.""FullName"" AS ""UploadedByName"", rl.""RoleName"" AS ""UploadedByRole"", pat.""FullName"" AS ""PatientName"",
            //                    prd.""ThumbnailUrl"" AS ""ThumbnailUrl"",
            //                    prd.""DocumentUrl"" AS ""DocumentUrl""
            //                    FROM ""PatientDocument"" prd
            //                    JOIN ""Patient"" pat ON pat.""PatientId"" = prd.""PatientId"" AND pat.""Active"" IS TRUE
            //                    JOIN ""Account"" act ON act.""AccountId"" = prd.""UploadedBy"" AND act.""Active"" IS TRUE
            //                    JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
            //                    {where} ORDER BY prd.""PatientDocumentId"" DESC";

            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", prd.""PatientId"", prd.""PatientDocumentId"", prd.""DocumentType"", prd.""DocumentName"", CASE WHEN prd.""Description"" IS NULL THEN '' ELSE prd.""Description"" END ""Description"", prd.""ContentType"", prd.""Size"",prd.""IsRead"",
                                prd.""UploadedDate"", prd.""UploadedBy"", act.""FullName"" AS ""UploadedByName"", rl.""RoleName"" AS ""UploadedByRole"", pat.""FullName"" AS ""PatientName"",
                                --(CASE WHEN prd.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', prd.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl"",
                                (CASE WHEN prd.""DocumentUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/',pat.""Guid"",'/',prd.""DocumentType"" ,'/', prd.""DocumentUrl"") ELSE NULL END) AS ""DocumentUrl""
                                FROM ""PatientDocument"" prd
                                JOIN ""Patient"" pat ON pat.""PatientId"" = prd.""PatientId"" AND pat.""Active"" IS TRUE
                                JOIN ""Account"" act ON act.""AccountId"" = prd.""UploadedBy"" AND act.""Active"" IS TRUE
                                JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
                                {where} ORDER BY prd.""PatientDocumentId"" DESC";

            if (model.PageIndex <= 0)
            {
                return this.unitOfWork.Current.QueryAsync<PatientDocumentModel>(query);
            }

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            return this.unitOfWork.Current.QueryAsync<PatientDocumentModel>(query);
        }

        /// <inheritdoc />
        public async Task<PatientDocumentModel> GetAsync(int id)
        {
            var record = await this.unitOfWork.PatientDocuments.FindAsync(x => x.PatientDocumentId == id);

            if (record != null)
            {
                return new PatientDocumentModel
                {
                    PatientDocumentId = record.PatientDocumentId,
                    PatientId = record.PatientId,
                    DocumentName = record.DocumentName,
                    DocumentType = record.DocumentType,
                    UploadedBy = record.UploadedBy,
                    UploadedDate = record.UploadedDate,
                    ModifiedBy = record.ModifiedBy,
                    ModifiedDate = record.ModifiedDate,
                    DocumentUrl = record.DocumentUrl
                };
            }

            return null;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<int>> AddAsync(IEnumerable<PatientDocumentModel> model)
        {
            var patientDocuments = model.Select(item => new PatientDocument
            {
                Active = true,
                PatientId = item.PatientId,
                UploadedBy = item.UploadedBy,
                DocumentName = item.DocumentName,
                DocumentType = item.DocumentType,
                ContentType = item.ContentType,
                Size = item.Size,
                Description = item.Description,
                DocumentUrl = item.DocumentUrl,
                ThumbnailUrl = item.ThumbnailUrl,
                UploadedDate = DateTime.UtcNow
            });
            var responseIds = new List<int>();
            foreach (var patientDocument in patientDocuments)
            {
                var response = await this.unitOfWork.PatientDocuments.InsertAsync(patientDocument);
                responseIds.Add(response);
            }

            return responseIds;
        }

        /// <inheritdoc />
        public Task<int> AddAsync(PatientDocumentModel model)
        {
            var patientDocument = new PatientDocument
            {
                Active = true,
                PatientId = model.PatientId,
                UploadedBy = model.UploadedBy,
                DocumentName = model.DocumentName,
                DocumentType = model.DocumentType,
                ContentType = model.ContentType,
                Size = model.Size,
                Description = model.Description,
                DocumentUrl = model.DocumentUrl,
                ThumbnailUrl = model.ThumbnailUrl,
                UploadedDate = DateTime.UtcNow
            };

            return this.unitOfWork.PatientDocuments.InsertAsync(patientDocument);
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(PatientDocumentModel model)
        {
            var patientDocument = await this.unitOfWork.PatientDocuments.FindAsync(m => m.PatientDocumentId == model.PatientDocumentId);
            patientDocument.DocumentName = model.DocumentName;
            //patientDocument.DocumentType = model.DocumentType;
            patientDocument.Description = model.Description;
            patientDocument.ModifiedBy = model.ModifiedBy;
            patientDocument.ModifiedDate = DateTime.UtcNow;

            return await this.unitOfWork.PatientDocuments.UpdateAsync(patientDocument);
        }

        /// <inheritdoc />
        public async Task<DeleteDocumentModel> DeleteAsync(ModifyPatientDocumentModel model)
        {
            var query = $@"SELECT ""Guid"", ""DocumentUrl"" FROM ""PatientDocument"" p JOIN ""Patient"" pat ON pat.""PatientId"" = p.""PatientId"" WHERE p.""PatientDocumentId"" = {model.PatientDocumentId} ";
            var result = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<DeleteDocumentModel>(query);

            query = $@"DELETE FROM ""PatientDocument"" WHERE ""PatientDocumentId""= {model.PatientDocumentId}";
            var deleted = await this.unitOfWork.Current.ExecuteAsync(query);

            return deleted > 0 ? result : null;
        }

        /// <inheritdoc />
        public Task<int> ModifyReadAsync(ModifyPatientDocumentModel model)
        {
            var query = $@"UPDATE ""PatientDocument"" SET ""IsRead"" = true, ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""PatientDocumentId""= {model.PatientDocumentId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        public Task<IEnumerable<PatientDocumentModel>> DownloadFetchFileFTP(PatientDocumentFilterModel model)
        {

            var where = string.Empty;

            if (model.PatientId != 0)
            {
                where = $@" WHERE prd.""Active"" IS TRUE AND prd.""PatientId"" = {model.PatientId}";
            }

            if (model.PatientDocumentId != null)
            {
                where = $@" and prd.""PatientDocumentId"" = {model.PatientDocumentId}";
            }

            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", prd.""PatientId"", prd.""PatientDocumentId"", prd.""DocumentType"", prd.""DocumentName"", CASE WHEN prd.""Description"" IS NULL THEN '' ELSE prd.""Description"" END ""Description"", prd.""ContentType"", prd.""Size"",prd.""IsRead"",
                                prd.""UploadedDate"", prd.""UploadedBy"", act.""FullName"" AS ""UploadedByName"", rl.""RoleName"" AS ""UploadedByRole"", pat.""FullName"" AS ""PatientName"", prd.""ThumbnailUrl"",
                                 pat.""Guid"", prd.""DocumentUrl"" AS ""DocumentUrl""
                                FROM ""PatientDocument"" prd
                                JOIN ""Patient"" pat ON pat.""PatientId"" = prd.""PatientId"" AND pat.""Active"" IS TRUE
                                JOIN ""Account"" act ON act.""AccountId"" = prd.""UploadedBy"" AND act.""Active"" IS TRUE
                                JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
                                {where} ORDER BY prd.""PatientDocumentId"" DESC";

            if (model.PageIndex <= 0)
            {
                return this.unitOfWork.Current.QueryAsync<PatientDocumentModel>(query);
            }

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            return this.unitOfWork.Current.QueryAsync<PatientDocumentModel>(query);

        }

        public async Task<PatientDocumentModel> GetPatientDocumentOnIdAsync(int id)
        {
            var query = $@"select * FROM ""PatientDocument"" where ""PatientDocumentId"" = {id}";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PatientDocumentModel>(query);
        }

        public async Task<ScanDocumentModel> GetScanDocumentOnIdAsync(int id)
        {
            var query = $@"select * FROM ""ScanDocument"" where ""ScanDocumentId"" = {id}";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<ScanDocumentModel>(query);
        }

        public async Task<PackageDocumentModel> GetPackageDocument(int id)
        {
            var query = $@"select * FROM ""PackageDocument"" where ""PackageDocumentId"" = {id}";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PackageDocumentModel>(query);
        }
    }
}