using LSFE.Domain.Contracts;
using LSFE.Infrastructure.Dto;
using LSFE.Infrastructure.Dto.Doctor;
using LSFE.Infrastructure.Dto.Maintenance;
using LSFE.Infrastructure.Dto.Planning;
using LSFE.Infrastructure.Entities.Maintenance;
using LSFE.Infrastructure.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;


namespace LSFE.API.Controllers
{
    public class PlanController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IWebHostEnvironment _env;
        public PlanController(IUnitOfWork unitOfWork, IWebHostEnvironment env) : base(unitOfWork, env)
        {
            _unitOfWork = unitOfWork;
            _env = env;
        }
        #region Post Put
        [HttpPost("PostActualCoveragePlan")]
        [RequestSizeLimit(15_000_000)]
        public async Task<IActionResult> PostActualCoveragePlan(
        [FromForm] MRRawPlansDto dto, IFormFile? photoFile)
        {
            if (dto == null)
                return await LogAndReturnBadRequest("Invalid attendance data.", "Unknown");

            try
            {
                await SaveSignatureAsync(photoFile, dto.SignatureFileName);

                if (dto.IsCatchUpCall)
                {
                    var plan = await _unitOfWork.CatchUpCalls
                        .FindAsync(p => p.MRRawPlanId == dto.MRRawPlanId);

                    if (plan == null)
                        return await LogAndReturnBadRequest("Plan not found", dto.UserId);

                    MapDtoToPlan(plan, dto);
                    await _unitOfWork.CatchUpCalls.AddOrUpdateAsync(plan);
                }
                else
                {
                    var plan = await _unitOfWork.MRRawPlans
                        .FindAsync(p => p.MRRawPlanId == dto.MRRawPlanId);

                    if (plan == null)
                        return await LogAndReturnBadRequest("Plan not found", dto.UserId);

                    MapDtoToPlan(plan, dto);
                    await _unitOfWork.MRRawPlans.AddOrUpdateAsync(plan);
                }

                var affected = await _unitOfWork.SaveChangesAsync();

                return BuildResponse(affected);
            }
            catch (Exception ex)
            {
                return await LogAndReturnBadRequest(ex.Message, dto.UserId);
            }
        }
        [HttpPost("PostPutPlan")]
        public async Task<IActionResult> PostPutPlan([FromBody] PlanningDto dto)
        {
            if (dto == null)
                return BadRequest("Invalid doctor data.");

            var response = await _unitOfWork.Planning.PostPutPlan(dto);
            return response.Success ? Ok(response) : BadRequest(response);
        }
        [HttpPost("CopyMonthlyMRRawPlans")]
        public async Task<IActionResult> CopyMonthlyMRRawPlans([FromBody] PlanningDto dto)
        {
            if (dto == null)
                return BadRequest("Invalid doctor data.");

            var response = await _unitOfWork.Planning.CopyMonthlyMRRawPlans(dto);
            return response.Success ? Ok(response) : BadRequest(response);
        }
        [HttpPost("ApprovePlan")]
        public async Task<IActionResult> ApprovePlan([FromBody] ApprovePlanDto dto)
        {
            if (dto == null)
                return BadRequest("Invalid doctor data.");

            var response = await _unitOfWork.Planning.ApprovePlan(dto);
            return response.Success ? Ok(response) : BadRequest(response);
        }
        [HttpDelete("{doctorId:int}")]
        public async Task<IActionResult> SoftDeleteAsync(int doctorId)
        {
            var result = await _unitOfWork.Planning.SoftDeleteAsync(doctorId);
            return result.Success ? Ok(result) : BadRequest(result);
        }
        #endregion
        #region Method Helper
        private async Task SaveSignatureAsync(IFormFile? file, string? fileName)
        {
            if (file == null || string.IsNullOrWhiteSpace(fileName))
                return;

            var uploadsPath = Path.Combine(
                _env.WebRootPath,
                "Content", "Uploads", "Signature");

            Directory.CreateDirectory(uploadsPath);

            var filePath = Path.Combine(uploadsPath, fileName);

            if (System.IO.File.Exists(filePath))
                return;

            await using var stream = new FileStream(filePath, FileMode.Create);
            await file.CopyToAsync(stream);
        }
        private static void MapDtoToPlan(dynamic plan, MRRawPlansDto dto)
        {
            plan.SignatureFileName = dto.SignatureFileName;
            plan.StartTime = dto.StartTime;
            plan.EndTime = dto.EndTime;
            plan.ActualCallDate = dto.ActualCallDate;
            plan.Longitude = dto.Longitude;
            plan.Latitude = dto.Latitude;
            plan.Location = dto.Location;
            plan.IsReschedule = dto.IsReschedule;
            plan.RescheduleReason = dto.RescheduleReason;
            plan.IsMissed = dto.IsMissed;
            plan.MissedReason = dto.MissedReason;
            plan.Status = dto.Status;
        }
        private IActionResult BuildResponse(int affectedRows)
        {
            var success = affectedRows > 0;

            var response = new Response
            {
                Success = success,
                MessCode = (byte)(success ? 1 : 0),
                Message = success
                    ? "Successfully saved and synced!"
                    : "Failed to save plan"
            };

            return success ? Ok(response) : BadRequest(response);
        }
        #endregion

        #region Get
        [HttpGet("GetAllAppointmentToday")]
        public async Task<IActionResult> GetAllAppointmentToday([FromQuery] CredentialDto dto)
        {
            var result = await _unitOfWork.Planning.GetAllAppointmentToday(dto);
            return Ok(result);
        }
        [HttpGet("GetAllMissReschedule")]
        public async Task<IActionResult> GetAllMissReschedule([FromQuery] CredentialDto dto)
        {
            var result = await _unitOfWork.Planning.GetAllMissReschedule(dto);
            return Ok(result);
        }
        [HttpGet("GetMRRawPlans")]
        public async Task<IActionResult> GetMRRawPlans([FromQuery] PlanByUserIdRequest dto)
        {
            var result = await _unitOfWork.Planning.GetMRRawPlans(dto);
            return Ok(result);
        }

        [HttpGet("GetDoctorProductToday")]
        public async Task<IActionResult> GetDoctorProductToday([FromQuery] CoverageDto dto)
        {
            try
            {
                var query = from prod in _unitOfWork.Products.Query()
                            join trans in _unitOfWork.ProductTransactions.Query()
                            on prod.ProductId equals trans.ProductId
                            where trans.UserId == dto.UserId
                            && trans.AppointmentDate == DateOnly.FromDateTime(DateTime.Now)
                            select new ProductTransactionDto
                            {
                                ProductId = trans.ProductId,
                                ProductName = trans.ProductName,
                                UserId = trans.UserId,
                                CreatedDate = trans.CreatedDate,
                                IsActive = trans.IsActive,
                                ProductTransId = trans.ProductTransId,
                                AppointmentDate = trans.AppointmentDate,
                                MRRawPlanId = trans.MRRawPlanId,
                                DoctorId = trans.DoctorId,
                                CreatedBy = trans.CreatedBy,
                                ProductLink = prod.ProductLink
                            };
                var result = await query.ToListAsync();

                return Ok(result);
            }
            catch (Exception ex)
            {
                ex.ToString();
                throw;
            }
        }
        [HttpGet("GetDoctorSampleToday")]
        public async Task<IActionResult> GetDoctorSampleToday([FromQuery] CoverageDto dto)
        {
            try
            {
                var query = from inv in _unitOfWork.Inventory.Query()
                            join trans in _unitOfWork.InventoryTransactions.Query()
                            on inv.InventoryId equals trans.InventoryId
                            where trans.UserId == dto.UserId
                            && trans.AppointmentDate == DateOnly.FromDateTime(DateTime.Now)
                            select new
                            {
                                inv.InventoryId,
                                inv.Description,
                                inv.UserId,
                                inv.CreatedDate,
                                inv.IsActive,
                                inv.QtyBalance,
                                trans.InventoryTransId,
                                trans.QtyIn,
                                trans.DoctorId,
                                trans.AppointmentDate,
                                trans.MRRawPlanId,
                                trans.IconEmojiId
                            };
                var result = await query.ToListAsync();

                return Ok(result);
            }
            catch (Exception e)
            {
                e.ToString();
                throw;
            }            
        }
        [HttpGet("GetDoctorWithPlan")]
        public async Task<IActionResult> GetDoctorWithPlan([FromQuery] DoctorDto dto)
        {
            var doctors = await _unitOfWork.Planning.GetDoctorWithPlan(dto);
            return Ok(doctors);
        }
        [HttpGet("GetDoctorById")]
        public async Task<IActionResult> GetDoctorById([FromQuery] DoctorDto dto)
        {
            var doctors = await _unitOfWork.Planning.GetDoctorById(dto);
            return Ok(doctors);
        }
        [HttpGet("GetSampleTransaction")]
        public async Task<IActionResult> GetSampleTransaction([FromQuery] Guid mrRawPlanId)
        {
            var sampleTrans = await _unitOfWork.Planning.GetSampleTransaction(mrRawPlanId);
            return Ok(sampleTrans);
        }
        [HttpGet("GetProductTransaction")]
        public async Task<IActionResult> GetProductTransaction([FromQuery] ProductTransaction dto)
        {
            var transactions = await _unitOfWork.Planning.GetProductTransaction(dto.MRRawPlanId);
            return Ok(transactions);
        }
        [HttpGet("GetPendingApprovals")]
        public async Task<IActionResult> GetPendingApprovals([FromQuery] PlanningDto dto)
        {
            var doctors = await _unitOfWork.Planning.GetPendingApprovals(dto);
            return Ok(doctors);
        }
        #endregion
    }
}
