namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Domain.Configurations;
    using Domain.Services;
    using Domain.Helpers;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Models.Ticket;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Serialization;

    using Shared.DataFilters;
    using Shared.UserModels.Insurance;
    using Utilities;

    /// <inheritdoc />
    [Authorize]
    [Route("api/insurance-approval")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class InsuranceApprovalController : BaseController
    {
        /// <summary>
        /// The insurance admission services.
        /// </summary>
        private readonly IInsuranceAdmissionService insuranceAdmissionServices;

        /// <summary>
        /// The amazon s3 helper.
        /// </summary>
        private readonly IDocumentHelper documentHelper;

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


        /// <summary>
        /// The insuranceCompany services.
        /// </summary>
        private readonly IInsuranceCompanyService insuranceCompaniesServices;

        /// <inheritdoc />
        public InsuranceApprovalController(IInsuranceAdmissionService insuranceAdmissionServices, IDocumentHelper documentHelper, IAmazonS3Configuration amazonS3Configuration, IInsuranceCompanyService insuranceCompaniesServices)
        {
            this.insuranceAdmissionServices = insuranceAdmissionServices;
            this.documentHelper = documentHelper;
            this.amazonS3Configuration = amazonS3Configuration;
            this.insuranceCompaniesServices = insuranceCompaniesServices;
        }

        /// <summary>
        /// The add insurance for admission.
        /// </summary>
        /// <param name="model">
        /// The model
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("modify-insurance-admission")]
        public async Task<ActionResult> AddInsuranceForAdmission([FromBody] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            var response = model.InsuranceForAdmissionId > 0 ? await this.insuranceAdmissionServices.UpdateInsuranceApproval(model) : await this.insuranceAdmissionServices.AddInsuranceForAdmission(model);
            return this.Success(response);
        }

        /// <summary>
        /// The add insurance for admission.
        /// </summary>
        /// <param name="model">
        /// The model
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("check-insurance-approval")]
        public async Task<ActionResult> CheckInsuranceApprovalExists([FromBody] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            if(model.AdmissionId > 0)
            {
                var response = await this.insuranceAdmissionServices.GetInsuranceAdmissionApproval((int)model.AdmissionId, (int)model.PatientInsuranceId);
                if (response != null)
                {
                    return this.Success("##### already Exists");
                }
                return this.Success();
            }
            if (model.AppointmentId > 0)
            {
                var response = await this.insuranceAdmissionServices.GetInsuranceAppointmentApproval((int)model.AppointmentId, (int)model.PatientInsuranceId);
                if (response != null)
                {
                    return this.Success("##### already Exists");
                }
                return this.Success();
            }
            return this.BadRequest();
        }

        /// <summary>
        /// The add insurance for admission.
        /// </summary>
        /// <param name="model">
        /// The model
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("add-insurance-approval")]
        public async Task<ActionResult> AddInsuranceApproval([FromBody] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            var response = model.InsuranceApprovalId > 0 ? await this.insuranceAdmissionServices.UpdateInsuranceApproval(model) : await this.insuranceAdmissionServices.AddInsuranceApproval(model);
            if(response <= 0)
            {
                return this.BadRequest();
            }
            return this.Success(response);
        }

        /// <summary>
        /// The get insurance based on admission id.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("get-admission-insurance")]
        public async Task<ActionResult> GetInsuranceBasedOnAdmissionId([FromBody] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            if (model.AdmissionId == null)
            {
                return this.BadRequest("Invalid parameter passed.");
            }
            var insuranceAdmission = await this.insuranceAdmissionServices.GetInsuranceForAdmission((int)model.AdmissionId);
            if (insuranceAdmission == null)
            {
                return null;
            }
            var companyName = await this.insuranceCompaniesServices.FindNameByInsuranceId(insuranceAdmission.InsuranceCompanyId);
            var response = new AdmissionInsuranceModel()
            {
                ExpectedAmount = insuranceAdmission.ExpectedAmount,
                AdmissionId = insuranceAdmission.AdmissionId,
                InsuranceCompanyId = insuranceAdmission.InsuranceCompanyId,
                InsuranceForAdmissionId = insuranceAdmission.InsuranceForAdmissionId,
                InsuranceCompanyName = !string.IsNullOrEmpty(companyName) ? companyName : null,
                ExpectedSettlementDate = insuranceAdmission.ExpectedSettlementDate
            };
            return this.Success(response);
        }



        /// <summary>
        /// The fetch all.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("fetch-all")]
        public async Task<ActionResult> FetchAll([FromBody] AdmissionInsuranceModel model)
        {
            model ??= new AdmissionInsuranceModel();
            var response = await this.insuranceAdmissionServices.FetchAll(model);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch all.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("fetch-all-insurance-approvals")]
        public async Task<ActionResult> FetchAllInsuranceApprovals([FromBody] AdmissionInsuranceModel model)
        {
            model ??= new AdmissionInsuranceModel();
            if(model.AdmissionId != null && model.AppointmentId != null)
            {
                return this.BadRequest("Something wrong");
            }
            if(model.AdmissionId != null && model.AdmissionId != 0 )
            {
                var response = await this.insuranceAdmissionServices.FetchAdmissionInsuranceApprovals(model);
                return this.Success(response);
            }
            if (model.AppointmentId != null && model.AppointmentId != 0)
            {
                var response = await this.insuranceAdmissionServices.FetchAppointmentInsuranceApprovals(model);
                return this.Success(response);
            }
            return this.BadRequest("Something wrong");

        }

        /// <summary>
        /// The insert insurance timeline async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("add-insurance-timeline")]
        [Consumes("multipart/form-data")]
        [Produces("application/json")]
        [ProducesResponseType(typeof(int), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> InsertInsuranceTimelineAsync([FromForm] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            var files = this.Request.Form.Files;
            var attachment = new List<Attachments>();

            if (files.Count != 0)
            {
                if (files.Count > 10)
                {
                    return this.BadRequest("Maximum of 10 files can be allowed to upload.");
                }

                var contentTypes = this.documentHelper.FetchContentTypes().ToList();

                if (!ListFilter.ContainsAll(contentTypes, files.Select(m => m.ContentType).Distinct()))
                {
                    return this.Failed($"Only {string.Join(", ", contentTypes)} files are allowed.");
                }

                var index = 0;

                foreach (var file in files)
                {
                    var fileName = $"attachment_{index}_{DateTime.UtcNow.Ticks}{System.IO.Path.GetExtension(file.FileName)}";
                    string fileUrl = string.Empty;
                    var url = await this.documentHelper.UploadAttachmentsAsync(file, model.InsuranceForAdmissionId.ToString(), "Insurance", fileName);
                    fileUrl = $@"{model.InsuranceForAdmissionId}/{url}";

                    var filesModel = new Attachments
                    {
                        FileName = file.FileName,
                        Url = $@"{this.amazonS3Configuration.BucketURL}{fileUrl}",
                        Extension = System.IO.Path.GetExtension(file.FileName)?.Split(".")[1]
                    };

                    attachment.Add(filesModel);
                    index++;
                }
            }

            if (attachment.Count > 0)
            {
                model.Attachments = JsonConvert.SerializeObject(attachment, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
            }

            var response = await this.insuranceAdmissionServices.InsertInsuranceTimeline(model);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch all insurance timeline async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("fetch-all-insurance-timeline")]
        public async Task<ActionResult> FetchAllInsuranceTimeline([FromBody] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            var response = await this.insuranceAdmissionServices.FetchAllInsuranceTimelineAsync((int)model.InsuranceForAdmissionId);
            return this.Success(response);
        }

        /// <summary>
        /// The get insurance based on admission id.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("get-insurance-approvals")]
        public async Task<ActionResult> FetchInsuranceApprovalsByAdmissionIdAysnc([FromBody] AdmissionInsuranceModel model)
        {
            model = (AdmissionInsuranceModel)EmptyFilter.Handler(model);
            if(model.AdmissionId > 0)
            {
                var response = await this.insuranceAdmissionServices.FetchInsuranceApprovalsByAdmissionIdAysnc((int)model.AdmissionId);
                if (response == null)
                {
                    return null;
                }
                return this.Success(response);
            }
            if (model.AppointmentId > 0)
            {
                var response = await this.insuranceAdmissionServices.FetchInsuranceApprovalsByAppointmentIdAysnc((int)model.AppointmentId);
                if (response == null)
                {
                    return null;
                }
                return this.Success(response);
            }
            return this.BadRequest();
        }
    }
}