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

    using Dapper;

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

    using Hims.Shared.EntityModels;
    using Hims.Shared.UserModels;

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

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

        /// <summary>
        /// The fetch async.
        /// </summary>
        /// <param name="appointmentId">
        /// The appointment id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<IEnumerable<VideoCallHistoryModel>> FetchAsync(int appointmentId)
        {
            var where = $@"WHERE 1 = 1";

            if (appointmentId > 0)
            {
                where = $@"WHERE a.""AppointmentId"" = {appointmentId}";
            }

            var query = $@"SELECT
	                                v.*,
	                                a.""AppointmentDate"",
	                                a.""AppointmentTime"",
	                                p.""FullName"" AS ""DoctorFullName"",
	                                pa.""FullName"" AS ""PatientFullName"",
                                    d.""Status"",
                                    d.""Reason""
                                FROM
	                                ""VideoCallHistory"" v
	                                LEFT JOIN ""Appointment"" A ON A.""AppointmentId"" = v.""AppointmentId""
	                                LEFT JOIN ""Provider"" P ON P.""ProviderId"" = A.""ProviderId""
	                                LEFT JOIN ""Patient"" pa ON pa.""PatientId"" = A.""PatientId""
                                    LEFT JOIN ""DoctorDeviceDetails"" d on d.""AppointmentId"" = v.""AppointmentId""
	                                
	                                {where} ORDER BY v.""VideoCallHistoryId"" desc LIMIT 10";
            var records = await this.unitOfWork.Current.QueryAsync<VideoCallHistoryModel>(query);
            return records;
        }

        /// <summary>
        /// The fetch async.
        /// </summary>
        /// <param name="appointmentId">
        /// The appointment id.
        /// </param>
        /// <param name="doctorDeviceDetailsId">
        /// The doctor device details id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<VideoCallHistoryInfo> FetchAsync(int appointmentId, int doctorDeviceDetailsId)
        {
            var where = $@"WHERE v.""AppointmentId"" = {appointmentId} AND v.""DoctorDeviceDetailsId"" = {doctorDeviceDetailsId}";

            var query = $@"SELECT
	                                v.*
                                FROM
	                                ""VideoCallHistory"" v
	                                
	                                {where} LIMIT 1";
            var record = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<VideoCallHistoryModel>(query);

            var history = new VideoCallHistoryInfo();
            query = $@"SELECT * FROM ""DoctorDeviceDetails"" WHERE ""DoctorDeviceDetailsId"" = {doctorDeviceDetailsId}";
            history.Doctor = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<DoctorDeviceDetailsModel>(query);

            if (record.PatientDeviceDetailsId > 0)
            {
                query = $@"SELECT * FROM ""PatientDeviceDetails"" WHERE ""PatientDeviceDetailsId"" = {record.PatientDeviceDetailsId}";
                history.Patient = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<PatientDeviceDetailsModel>(query);
            }

            return history;
        }

        /// <summary>
        /// The insert async.
        /// </summary>
        /// <param name="appointmentId">
        /// The appointment id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<int> InsertAsync(int appointmentId)
        {
            var query = $@"SELECT ""DoctorDeviceDetailsId""
                                FROM
	                            ""DoctorDeviceDetails"" WHERE ""AppointmentId"" = {appointmentId} ORDER BY ""DoctorDeviceDetailsId"" desc LIMIT 1";
            var doctorDeviceDetailsId = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int?>(query);

            query = $@"SELECT ""PatientId""
                                FROM
	                            ""Appointment"" WHERE ""AppointmentId"" = {appointmentId} LIMIT 1";
            var patientId = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int?>(query);

            query = $@"SELECT ""PatientDeviceDetailsId""
                                FROM
	                            ""PatientDeviceDetails"" WHERE ""PatientId"" = {patientId} ORDER BY ""PatientDeviceDetailsId"" desc LIMIT 1";
            var patientDeviceDetailsId = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int?>(query);

            var data = new VideoCallHistory
            {
                AppointmentId = appointmentId,
                DoctorDeviceDetailsId = doctorDeviceDetailsId ?? 0,
                PatientDeviceDetailsId = patientDeviceDetailsId ?? 0
            };

            var response = await this.unitOfWork.VideoCallHistories.InsertAsync(data);
            return response;
        }
    }
}