using AutoMapper;
using JobPortalAPI.DTOs;
using JobPortalAPI.Models;
using JobPortalAPI.UnitOfWork;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Build.Tasks.Deployment.Bootstrapper;
using Microsoft.EntityFrameworkCore;
using System;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Net;
using Microsoft.AspNetCore.Identity;
using JobPortalAPI.Notifications;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace JobPortalAPI.Controllers
{
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

    [Route("api/[controller]")]
    [ApiController]
    public class JobSeekersController : BaseController
    {
        private readonly IMapper _mapper;
        protected readonly JobPortalDBContext Context;
        private readonly UserManager<IdentityUser> _userManager;
        private readonly IHubContext<NotificationHub> _hubContext;

        private readonly IConfiguration _configuration;
        private DbSet<JobSeeker> _dbSet;

        public JobSeekersController(IUnitOfWork unitOfWork, IMapper mapper, JobPortalDBContext context, UserManager<IdentityUser> userManager, IConfiguration configuration, IHubContext<NotificationHub> hubContext)
            : base(unitOfWork)
        {
            _mapper = mapper;
            Context = context;
            _dbSet = Context.Set<JobSeeker>();
            _userManager = userManager;
            _configuration = configuration;
            _hubContext = hubContext;

        }
        [HttpGet]
        public IActionResult GetJobSeekers()
        {

            var jobSeekers = _unitOfWork.JobSeekerRepo.GetAllDetails();
            if (jobSeekers != null)
            {
                List<JobSeekerDto> x = new List<JobSeekerDto>();
                x = _mapper.Map<List<JobSeekerDto>>(jobSeekers);
                
                return Ok(x);   
            }
            else
            {
                return NotFound("xxxxxxxxxxxxxx");
            }
        }
        [HttpGet("GetJobseekerNameById/{id}")]
        public IActionResult GetJobseekerNameById(int id)
        {

            var x = _unitOfWork.PersonRepo.Get(id);
            if (x != null)
            {
                String name;
                name = x.Name;
                return Ok(name);

            }
            else
            {
                return Ok("this jobseeker doesn't exist!!!");
            }
        }
        [HttpGet("isApplied/{jobId}/{jobSeekerId}")]
        public IActionResult isApplied(int jobId, int jobSeekerId)
        {
            if(ModelState.IsValid)
            {
                bool x;
                var entyJob = _unitOfWork.JobEntryRepo.GetAll().FirstOrDefault(e => e.JobId == jobId && e.JobSeekerId == jobSeekerId);
                if (entyJob != null)
                {
                    x = true;

                }
                else
                {
                    x = false;
                }
                return Ok(x);
            }
            else
            {
                return BadRequest();
            }
        }
        [HttpGet("isBooked/{jobId}/{jobSeekerId}")]
        public IActionResult isBooked(int jobId, int jobSeekerId)
        {
            if (ModelState.IsValid)
            {
                InterviewDto inter = new InterviewDto();
                var interview = _unitOfWork.InterviewRepo.GetAll().FirstOrDefault(i => i.JobId == jobId && i.JobSeekerId == jobSeekerId);
             
                if (interview != null)
                {
                    var jobseeker = _unitOfWork.PersonRepo.Get(interview.JobSeekerId);
                    var company = _unitOfWork.PersonRepo.Get(interview.CompanyId);
                    var job = _unitOfWork.JobRepo.Get(interview.JobId);
                    inter = _mapper.Map<InterviewDto>(interview);
                    inter.Name = jobseeker.Name;
                    var filePath = Path.Combine("Images", jobseeker.Image);
                    inter.Image = filePath;
                    return Ok(inter);
                }
                return Ok();
               
            }
            else
            {
                return BadRequest();
            }
        }

        [HttpGet("{id}")]
        public IActionResult Get(int id)
        {
            var jobseeker = _unitOfWork.JobSeekerRepo.GetAllDetails().FirstOrDefault(js => js.Id == id);
            JobSeekerDto x = new JobSeekerDto();

            if (jobseeker == null)
            {
                return NotFound();
            }
            else
            {
                x = _mapper.Map<JobSeekerDto>(jobseeker);
            }
           
            return Ok(x);
        }
        [AllowAnonymous]
        [HttpPost]
        public async Task<IActionResult> Register([FromForm] PersonJobSeekerDto dto)
        {
            if (ModelState.IsValid)
            {
                var user_exist = await _userManager.FindByEmailAsync(dto.Email);
                if (user_exist != null)
                {
                    return BadRequest
                    (
                         new AuthResult()
                         {
                             result = false,
                             Errors = new List<string>()
                            {
                                "Email already exist"
                            }

                         }
                    );
                }
                if (!CheckPhoneNumber(dto.Phone))
                {
                    return BadRequest(new AuthResult() { Errors = new List<string>() { "Enter a valid phone number" } });
                }
                var userid = Guid.NewGuid().ToString();
                var new_user = new IdentityUser()
                {
                    Email = dto.Email,
                    UserName = $"{dto.Name}{userid}"

                };
                var is_created = await _userManager.CreateAsync(new_user, dto.Password);
                if (!(is_created.Succeeded))
                {
                    return BadRequest(new AuthResult() { Errors = new List<string>() { "Enter a valid password" } });
                }
               
                var person = _mapper.Map<Person>(dto);
                var jobSeeker = _mapper.Map<JobSeeker>(dto);

                var cv = _mapper.Map<Cv>(dto);
                string currentDirectory = Directory.GetCurrentDirectory();
                if (dto.Image != null && dto.Image.Length > 0)
                {
                    var fileName = Guid.NewGuid().ToString() + Path.GetExtension(dto.Image.FileName);
                    var filePath = Path.Combine("Images", fileName);
                    var fullfilePath = Path.Combine("wwwroot", filePath);
                    var fullPath = Path.Combine(currentDirectory, fullfilePath);
                    using (var stream = new FileStream(fullPath, FileMode.Create))
                    {
                        dto.Image.CopyTo(stream);
                    }
                    person.Image = fileName;

                }

                else
                {
                    return BadRequest(new AuthResult() { Errors = new List<string>() { "Image is required" } });

                }

                jobSeeker.IdNavigation = person;

                var specification = _unitOfWork.SpecificationRepo.GetAll().FirstOrDefault(s => s.Name == dto.SpecificationName.ToUpper());
                if (specification == null)
                {
                    specification = new Specification
                    {
                        Name = dto.SpecificationName.ToUpper()
                    };
                    _unitOfWork.SpecificationRepo.Add(specification);
                    _unitOfWork.SaveChanges();
                }

                jobSeeker.Specification = specification;
                jobSeeker.SpecificationId = specification.Id;
                jobSeeker.Cv = cv;
                cv.IdNavigation = jobSeeker;

                _unitOfWork.PersonRepo.Add(person);
                _unitOfWork.SaveChanges();
                _unitOfWork.CvRepo.Add(cv);
                _unitOfWork.SaveChanges();
                
                return Ok();
            }
            else
            {
                return BadRequest(new AuthResult() { Errors = new List<string>() { "Enter valid values" } });
            }

}
        [HttpPut("{id}")]
        public async Task<IActionResult> updateAsync(int id ,[FromForm] UpdateJobseekerDto dto)
        {
            if (ModelState.IsValid)
            {
                var person = _unitOfWork.PersonRepo.Get(id);
                var jobseeker = _unitOfWork.JobSeekerRepo.GetAllWithSpecification().FirstOrDefault(js => js.Id == id);
                var cv = _unitOfWork.CvRepo.Get(id);
                if (jobseeker == null || person == null || cv == null)
                {
                    return NotFound();
                }
                else
                {
                    string currentDirectory = Directory.GetCurrentDirectory();
                    var currentImage = person.Image;
                    var currentImagePath = Path.Combine("Images", person.Image);
                    var fullcurrentImagePath = Path.Combine("wwwroot", currentImagePath);
                    var currentImagefullPath = Path.Combine(currentDirectory, fullcurrentImagePath); 
                    person.Address = dto.Address;
                    var user = await _userManager.FindByEmailAsync(person.Email);
                    if (user != null)
                    {

                        await _userManager.SetEmailAsync(user, dto.Email);
                    }
                    person.Email = dto.Email;
                   

                    person.Phone = dto.Phone;

                    person.Name = dto.Name;
                    if (dto.Image != null && dto.Image.Length > 0)
                    {
                        var fileName = Guid.NewGuid().ToString() + Path.GetExtension(dto.Image.FileName);
                        var filePath = Path.Combine("Images", fileName);
                        var fullfilePath = Path.Combine("wwwroot", filePath);
                        var fullPath = Path.Combine(currentDirectory, fullfilePath);
                        using (var stream = new FileStream(fullPath, FileMode.Create))
                        {
                            dto.Image.CopyTo(stream);
                        }
                        if (!string.IsNullOrEmpty(currentImagefullPath) && System.IO.File.Exists(currentImagefullPath))
                        {
                            System.IO.File.Delete(currentImagefullPath);
                        }
                        person.Image = fileName;

                    }
                    else if (!string.IsNullOrEmpty(currentImage))
                    {
                        person.Image = currentImage;
                    }
                    _unitOfWork.PersonRepo.Update(person);
                    _unitOfWork.SaveChanges();
                    jobseeker.Birthdate= dto.Birthdate;
                    jobseeker.Gender = dto.Gender;
                    cv.PreviousWorks = dto.PreviousWorks;
                    cv.Stages = dto.Stages;
                    cv.Certificate = dto.Certificate;
                    cv.Languages = dto.Languages;
                    jobseeker.Cv = cv;
                    if (dto.SpecificationName != null && dto.SpecificationName != jobseeker.Specification.Name.ToUpper())
                    {
                        var specification = _unitOfWork.SpecificationRepo.GetAll().FirstOrDefault(s => s.Name == dto.SpecificationName.ToUpper());
                        if (specification == null)
                        {
                            specification = new Specification
                            {
                                Name = dto.SpecificationName.ToUpper()
                            };
                            _unitOfWork.SpecificationRepo.Add(specification);
                            _unitOfWork.SaveChanges();
                            jobseeker.Specification = specification;
                            jobseeker.SpecificationId = specification.Id;
                        }
                        else
                        {
                            jobseeker.Specification = specification;
                            jobseeker.SpecificationId = specification.Id;
                        }
                       

                    }
                    _unitOfWork.JobSeekerRepo.Update(jobseeker);
                    _unitOfWork.SaveChanges();
                    
                   
                    return Ok();

                }
            }
            else
                {
                    return BadRequest(new AuthResult() { Errors = new List<string>() { "Enter valid values" } });
                }

            }
        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
            {
                var jobseeker = _unitOfWork.JobSeekerRepo.Get(id);
                var person = _unitOfWork.PersonRepo.Get(id);
                var cv = _unitOfWork.CvRepo.Get(id);

            if (jobseeker == null || cv == null || person == null)
                {
                    return NotFound();
                }
            string currentDirectory = Directory.GetCurrentDirectory();
            var currentImage = person.Image;
            var currentImagePath = Path.Combine("Images", person.Image);
            var fullcurrentImagePath = Path.Combine("wwwroot", currentImagePath);
            var currentImagefullPath = Path.Combine(currentDirectory, fullcurrentImagePath);
            if (!string.IsNullOrEmpty(currentImagefullPath) && System.IO.File.Exists(currentImagefullPath))
            {
                System.IO.File.Delete(currentImagefullPath);
            }
            var x = _unitOfWork.CvSkillRepo.GetAll().Where(cs => cs.Cvid == id);
            foreach (var cs in x)
            {
                _unitOfWork.CvSkillRepo.Remove(cs);
                _unitOfWork.SaveChanges();
            }
            _unitOfWork.CvRepo.Remove(cv);
            _unitOfWork.JobSeekerRepo.Remove(jobseeker);
            _unitOfWork.PersonRepo.Remove(person);
            _unitOfWork.SaveChanges();
            return Ok();
            }

        [HttpPost("AddJobRequest")]
        public async Task<IActionResult> AddJobRequestAsync(JobRequestDto dto)
        {
            if(ModelState.IsValid)
            {
                var job = _unitOfWork.JobRepo.Get(dto.JobId);
                var jobseeker = _unitOfWork.JobSeekerRepo.GetAllDetails().FirstOrDefault(js => js.Id == dto.JobSeekerId);
                JobEntry jobEntry = new JobEntry();
                jobEntry.JobSeekerId = dto.JobSeekerId;
                jobEntry.JobId = dto.JobId;
                jobEntry.Date = DateTime.Now;
                _unitOfWork.JobEntryRepo.Add(jobEntry);
                _unitOfWork.SaveChanges();
                Notification notification = new Notification();
                notification.JobSeekerId = dto.JobSeekerId;
                notification.CompanyId = job.CompanyId;
                notification.JobId = job.Id;
                notification.ToCompany = true;
                notification.IsRead = false;
                notification.Date = DateTime.Now;
                String details = $"Hello, my name is {jobseeker.IdNavigation.Name}, and I want to apply for {job.Name} work, so please book an interview for me";
                notification.Details = details;
                _unitOfWork.NotificationRepo.Add(notification);
                _unitOfWork.SaveChanges();
                await _hubContext.Clients.Group($"companyId_{job.CompanyId}").SendAsync("ReceiveNotification", "new notification message");
                return Ok(notification.Id);
            }
            else
            {
                return BadRequest(new AuthResult() { Errors = new List<string>() { "Enter valid values" } });
            }
        }
        [HttpDelete("RemoveJobRequest")]
        public IActionResult RemoveJobRequest(JobRequestDto dto)
        {
          if(ModelState.IsValid)
            {
                var jobEntry = _unitOfWork.JobEntryRepo.GetAll().FirstOrDefault(j => j.JobId == dto.JobId && j.JobSeekerId == dto.JobSeekerId);
                _unitOfWork.JobEntryRepo.Remove(jobEntry);
                _unitOfWork.SaveChanges();
                var job = _unitOfWork.JobRepo.Get(dto.JobId);
                var notification = _unitOfWork.NotificationRepo.GetAll().FirstOrDefault(n => n.JobSeekerId == dto.JobSeekerId && n.CompanyId == job.CompanyId && n.JobId == dto.JobId && n.ToCompany == true);
                if(notification != null)
                {
                    var note = _unitOfWork.NotificationRepo.Get(notification.Id);

                    _unitOfWork.NotificationRepo.Remove(note);
                    _unitOfWork.SaveChanges();
                    return Ok(note.Id);

                }
            }
            return BadRequest(new AuthResult()
            {
                Errors = new List<string>()
                            {
                                "Enter valid values"
                            }

            });

        }
        bool CheckPhoneNumber(String phonenumber)
        {
            bool x;
            if (phonenumber.Length == 10)
            {
                if (phonenumber[0] == '0' && phonenumber[1] == '9')
                {
                    x = true;
                    return x;
                }
                else
                {
                    x = false;
                    return x;
                }
            }
            else
            {
                x = false;
                return x;
            }
        }

    }

   



}

