using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;
using Sevomin.Models;
using Sevomin.Models.Enums;
using Sevomin.Models.Helpers;
using Sevomin.Models.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace Sevomin.WebFrontend.Controllers
{
	public class JobController : AuthorizedController
	{
		IJobRepository _jobRepository;		
		private HttpContextBase _httpContext;

		public JobController()
			: this(JobRepository.Current, 
			new SevominUserManager(new UserStore<User>(SevominDbContext.Current)), null)
		{
		}

		protected override void Initialize(System.Web.Routing.RequestContext requestContext)
		{
			base.Initialize(requestContext);
			_httpContext = requestContext.HttpContext;
		}

		public JobController(IJobRepository jobRepository, SevominUserManager userManager, HttpContextBase httpContext) : base(userManager)
		{
			_jobRepository = jobRepository;			
			_httpContext = httpContext;
		}

		private async Task<Job> GetEmptyJob()
		{
			User u = await UserManager.FindByNameAsync(User.Identity.Name);
			if (u == null)
				throw new InvalidOperationException("شما خیلی هنرمندی! به ما هم بگو چجوری!");
			Avalin avalin = u as Avalin;
			if (avalin == null)
				throw new InvalidOperationException("جای شما که اینجا نیست!");
			Job job = _jobRepository.GetEmptyJobFor(avalin);
			return job;
		}

        [Authorize(Roles = "Avalin")]
		public async Task<ActionResult> NewJob()
		{
            Avalin u = await UserManager.FindByNameAsync(User.Identity.Name) as Avalin;
            Job job = await GetEmptyJob();
            JobViewModel jvm = new JobViewModel(job);

            if (u == null)
                throw new InvalidOperationException();
            if (!u.EmailConfirmed)
            {
                ViewBag.Result = new PostResultViewModel(false, "ایمیل شما در سایت تایید نشده است. لطفا پس از تایید ایمیل برای تعریف این فرصت شغلی اقدام نمایید.");
                return View(jvm);
            }
			
			return View(jvm);
		}

        [Authorize(Roles = "Avalin")]
		[HttpPost]
		public async Task<ActionResult> NewJob(string JalaliExpireDate, string ContactPersonName,
			string ContactPersonPhone, string ContactPersonEMail, bool IsFullTime, 
			bool ShowCompanyName, string Description, bool ShowCompanyLogo, ResumeTypes ResumeType, FormCollection form)
		{
            Avalin u = await UserManager.FindByNameAsync(User.Identity.Name) as Avalin;
			Job job = await GetEmptyJob();
            if (u == null)
                throw new InvalidOperationException();
            if (!u.EmailConfirmed)
            {
                ViewBag.Result = new PostResultViewModel(false, "ایمیل شما در سایت تایید نشده است. لطفا پس از تایید ایمیل برای تعریف این فرصت شغلی اقدام نمایید.");
                return View(new JobViewModel(job));
            }

			try
			{
				UpdateFields(JalaliExpireDate, ContactPersonName, ContactPersonPhone,
					ContactPersonEMail, IsFullTime, ShowCompanyName,
					Description, ShowCompanyLogo, ResumeType, form, job);
				JobRepository.Current.Save();

                ViewBag.Result = new PostResultViewModel(true, "آگهی شما با موفقیت منتشر شد.");

                return RedirectToAction("SingleJob", new { jobId = job.Id });
			}
			catch (Exception)
			{
                ViewBag.Result = new PostResultViewModel(true, "در انتشار آگهی خطایی پیش آمده.");
                return View(new JobViewModel(job));
			}
		}

		private async Task<Job> FetchJob(long id)
		{
			User u = await UserManager.FindByNameAsync(User.Identity.Name);
			if (u == null)
				throw new InvalidOperationException("شما خیلی هنرمندی! به ما هم بگو چجوری!");
			Avalin avalin = (Avalin)u;
			Job job = _jobRepository.Find(id);
			if (job == null || job.AvalinId != avalin.Id)
				throw new InvalidOperationException("شماره آگهی استخدام مورد نظر معتبر نیست");
			return job;
		}

		[Authorize(Roles= "Avalin")]
        public async Task<ActionResult> Edit(long id)
		{
			Job job = await FetchJob(id);

            if (job.AvalinId != (await UserManager.FindByNameAsync(User.Identity.Name)).Id)
                return HttpNotFound();

			JobViewModel jvm = new JobViewModel(job);
			return View(jvm);
		}

		[HttpPost]
		public async Task<ActionResult> Edit(long id, string JalaliExpireDate, string ContactPersonName,
			string ContactPersonPhone, string ContactPersonEMail, bool IsFullTime,
			bool ShowCompanyName, string Description, bool ShowCompanyLogo, ResumeTypes ResumeType, FormCollection form)
		{
			Job job = await FetchJob(id);

            if (job.AvalinId != (await UserManager.FindByNameAsync(User.Identity.Name)).Id)
                return HttpNotFound();

			try
			{
				UpdateFields(JalaliExpireDate, ContactPersonName, ContactPersonPhone, 
					ContactPersonEMail, IsFullTime, ShowCompanyName, 
					Description, ShowCompanyLogo, ResumeType, form, job);
				JobRepository.Current.Save();

                ViewBag.Result = new PostResultViewModel(true, "آگهی شما با موفقیت به روز رسانی شد.");

                return View(new JobViewModel(job));
			}
			catch (Exception)
			{
                ViewBag.Result = new PostResultViewModel(false, "در به روز رسانی آگهی خطایی پیش آمد.");
				
                return View(new JobViewModel(job));
			}
		}

        [AllowAnonymous]
        public ActionResult RecentJobs()
        {
            return View(_jobRepository.ListAll()
                .Where(d => d.ExpireDate >= DateTime.Now)
                .OrderByDescending(d => d.ExpireDate)
                .ToList()
                .Select(j => new JobMiniViewModel(j)).ToList());
        }

        [AllowAnonymous]
        public PartialViewResult LatestJobList(int count)
		{
            return PartialView("JobList", _jobRepository.ListAll()
				.Where(d => d.ExpireDate >= DateTime.Now)
				.OrderByDescending(d => d.CreateDate)
				.Take(count)
				.ToList()
				.Select(j => new JobMiniViewModel(j)).ToList());
		}

        [AllowAnonymous]
        public ActionResult SingleJob(long jobId)
        {
            Job job = _jobRepository.Find(jobId);
            if (job == null)
                return HttpNotFound();

            JobViewModel viewModel = new JobViewModel(job);
            JobMiniViewModel jvm = new JobMiniViewModel(job, 3);
            StringBuilder sb = new StringBuilder("کارشناس برنامه ریزی و کنترل پروژه ");
            foreach (var param in jvm.Parameters)            
                sb.Append(string.Format(param.Item1 + " ", param.Item2));            

            ViewBag.ShortJobDescription = sb.ToString();

            return View(viewModel);
        }

        [Authorize(Roles = "Dovomin")]
        public async Task<ActionResult> Apply(long jobId)
        {
            Dovomin user = (await UserManager.FindByNameAsync(User.Identity.Name)) as Dovomin;
            Job job = _jobRepository.Find(jobId);
            if (user == null || job == null)
                return HttpNotFound();
            
            bool alreadyApplied = job.Applications.Any(a => a.DovominId == user.Id);
            DovominJob dj = alreadyApplied ? job.Applications.First(a => a.DovominId == user.Id) : new DovominJob(user, job);
            dj.CalculateAffinity();

            PrepareJobApplication(user, job, alreadyApplied);

            return View(new DovominJobViewModel(dj));
        }        

        [Authorize(Roles = "Dovomin")]
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Apply(long jobId, string CoverLetter)
        {
            Dovomin user = (await UserManager.FindByNameAsync(User.Identity.Name)) as Dovomin;
            Job job = _jobRepository.Find(jobId);
            if (user == null || job == null)
                return HttpNotFound();

            bool alreadyApplied = job.Applications.Any(a => a.DovominId == user.Id);                        
            PrepareJobApplication(user, job, alreadyApplied);
            DovominJob dj = alreadyApplied ? job.Applications.First(a => a.DovominId == user.Id) : new DovominJob(user, job);
            dj.CalculateAffinity();

            if (alreadyApplied)
            {
                ViewBag.Result = new PostResultViewModel(false, "اعلام آمادگی شما برای این فرصت شغلی قبلا ثبت شده است.");
                return View(new DovominJobViewModel(dj));
            }
            else if (!user.EmailConfirmed)
            {                                
                ViewBag.Result = new PostResultViewModel(false, "ایمیل شما در سایت تایید نشده است. لطفا پس از تایید ایمیل خود، مجددا برای این فرصت شغلی اعلام آمادگی نمایید.");
                return View(new DovominJobViewModel(dj));
            }

            dj = _jobRepository.Apply(user, job, CoverLetter);                        
            ViewBag.Result = new PostResultViewModel(true, "اعلام آمادگی شما برای این فرصت شغلی ثبت شد.");
            return View(new DovominJobViewModel(dj));
        }
        
        public ActionResult MyJobs(int? count)
        {            
            User user = UserManager.FindByName(User.Identity.Name);

            List<JobMiniViewModel> retList = new List<JobMiniViewModel>();

            if (user is Avalin)
                retList = _jobRepository.ListAll()
                    .Where(j => j.AvalinId == user.Id)
                    .OrderByDescending(j => j.CreateDate)
                    .ToList()
                    .Select(j => new JobMiniViewModel(j))
                    .ToList();
            else
                retList = _jobRepository.ListAll()
                    .Where(j => j.Applications.Any(a => a.DovominId == user.Id))
                    .OrderByDescending(j => j.CreateDate)
                    .ToList()
                    .Select(j => new JobMiniViewModel(j))
                    .ToList();

            return PartialView("JobList", retList);
        }

        [Authorize(Roles = "Avalin")]
        public ActionResult JobRequests()
        {
            Avalin user = UserManager.FindByName(User.Identity.Name) as Avalin;

            if (user == null)
                return HttpNotFound();

            var applications = SevominDbContext.Current.DovominJobs
                .Where(a => a.Job.AvalinId == user.Id)                
                .OrderByDescending(a => a.ApplyDate)
                .ToList()
                .Select(a => new JobApplicationViewModel(a));

            return PartialView(applications);
        }

        private void PrepareJobApplication(Dovomin user, Job job, bool alreadyApplied = true)
        {                        
            JobMiniViewModel jvm = new JobMiniViewModel(job, 3);
            StringBuilder sb = new StringBuilder("کارشناس برنامه ریزی و کنترل پروژه ");
            foreach (var param in jvm.Parameters)
                sb.Append(string.Format(param.Item1 + " ", param.Item2));

            ViewBag.ShortJobDescription = sb.ToString();
            ViewBag.Job = new JobViewModel(job);
            ViewBag.AlreadyApplied = alreadyApplied;
        }

		private static void UpdateFields(string JalaliExpireDate, string ContactPersonName, string ContactPersonPhone, string ContactPersonEMail, bool IsFullTime, bool ShowCompanyName, string Description, bool ShowCompanyLogo, ResumeTypes ResumeType, FormCollection form, Job job)
		{
			job.ExpireDate = DateAssist.ToMiladi(JalaliExpireDate);
			job.ContactPersonEMail = ContactPersonEMail;
			job.ContactPersonName = ContactPersonName;
			job.ContactPersonPhone = ContactPersonPhone;
			job.Description = Description;
			job.IsFullTime = IsFullTime;
			job.ShowCompanyLogo = ShowCompanyLogo;
			job.ShowCompanyName = ShowCompanyName;
            job.ResumeType = (byte)ResumeType;
			foreach (var jp in job.JobParameters)
			{
				string value = form[string.Format("value-{0}", jp.Parameter.Id)];
				byte moscow = 0;
				byte.TryParse(form[string.Format("moscow-{0}", jp.Parameter.Id)], out moscow);
				jp.SetValue(value);
                if (jp.Parameter.Moscow)
                {
                    if (string.IsNullOrWhiteSpace(jp.StringValue))
                        jp.Moscow = 0;
                    else
                        jp.Moscow = moscow;
                }
                else
                {
                    jp.Moscow = 4;
                }
			}
		}
	}
}