using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using ResourcesManager.Models;
using Microsoft.AspNet.Identity;
using System.IO;
using ResourcesManager.Helpers;
using ResourcesManager.Interfaces;
using ResourcesManager.Handlers;
using ResourcesManager.Repositories;

namespace ResourcesManager.Controllers
{
    [Authorize]
    public class ReservationsController : Controller
    {
        private ApplicationDbContext context;
        private IReservationRepository reservRepo;
        private IUserRepository userRepo;
        private IResourceRepository resourceRepo;
        private IStatisticRepository statRepo;
        readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public ReservationsController()
        {
            context = new ApplicationDbContext();
            reservRepo = new ReservationRepository(context);
            userRepo = new UserRepository(context);
            resourceRepo = new ResourceRepository(context);
            statRepo = new StatisticRepository(context);
        }
        public ReservationsController(IReservationRepository reservRepo, IUserRepository userRepo, IResourceRepository resourceRepo, IStatisticRepository statRepo)
        {
            this.reservRepo = reservRepo;
            this.userRepo = userRepo;
            this.resourceRepo = resourceRepo;
            this.statRepo = statRepo;
        }

        public ActionResult Index(int? year = null, int? month = null, int? resourceId = null)
        {
            try
            {
                if (year == null)
                {
                    year = DateTime.Now.Year;
                }
                if (month == null)
                {
                    month = DateTime.Now.Month;
                }

                var model = new ReservationViewModel();

                var startOfMonth = new DateTime((int)year, (int)month, 1);
                var endOfMonth = startOfMonth.AddMonths(1);
                model.Actual = startOfMonth;

                var startShift = -1 * ((int)startOfMonth.DayOfWeek - 1);
                startOfMonth = startOfMonth.AddDays(startShift);
                var endShift = 7 - ((int)endOfMonth.DayOfWeek - 1);
                endOfMonth = endOfMonth.AddDays(endShift == 7 ? 0 : endShift);
                model.Start = startOfMonth;
                model.End = endOfMonth;

                var reservations = reservRepo.GetReservations()
                    .ToList()
                    .OrderBy(x => x.Begining)
                    .Where(x => x.Begining > startOfMonth && x.Begining < endOfMonth)
                    .ToList();
                model.Reservations = reservations;
                return View(model);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        public ActionResult Week(DateTime date)
        {
            try
            {
                var startShift = -1 * ((int)date.DayOfWeek - 1);
                var endShift = 7 - ((int)date.DayOfWeek - 1);
                var startDay = date.AddDays(startShift);
                var endDay = date.AddDays(endShift);

                var reservations = reservRepo.GetReservations()
                    .ToList()
                    .OrderBy(x => x.Begining)
                    .Where(x => x.Begining > startDay && x.Begining < endDay)
                    .ToList();

                var model = new ReservationViewModel()
                {
                    Actual = date,
                    Start = startDay,
                    End = endDay,
                    Reservations = reservations
                };

                return View(model);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        public ActionResult Day(DateTime day)
        {
            try
            {
                var end = day.AddDays(1);
                var reservations = reservRepo.GetReservations()
                    .ToList()
                    .OrderBy(x => x.Begining)
                    .Where(x => x.Begining > day && x.Begining < end)
                    .ToList();

                var model = new ReservationViewModel()
                {
                    Actual = day,
                    Reservations = reservations
                };

                return View(model);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                log.Warn("BadRequest");
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Reservation reservation = reservRepo.GetReservationByID((int)id);
            if (reservation == null)
            {
                log.Warn("HttpNotFound");
                return HttpNotFound();
            }
            return View(reservation);
        }

        public ActionResult Create(int? resourceId, DateTime? time = null)
        {
            try
            {
                var model = new ReservationCreateViewModel()
                {
                    Reservation = new Reservation()
                };
                if (resourceId != null)
                {
                    model.Reservation.Begining = DateTime.Now.AddHours(1);
                    model.Reservation.End = DateTime.Now.AddHours(2);
                    model.Reservation.ResourceId = (int)resourceId;
                    model.Reservation.Resource = resourceRepo.GetResourceByID((int)resourceId);
                }
                else
                {
                    model.Reservation.Begining = (DateTime)time;
                    model.Reservation.End = ((DateTime)time).AddHours(1);
                    model.Resources = resourceRepo.GetResouces().ToList();
                }
                return View(model);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Reservation model)
        {
            try
            {
                model.Resource = resourceRepo.GetResourceByID(model.ResourceId);
                model.User = User.Identity.Name;
                if (model.Resource.TimeLimit != null)
                {
                    TimeSpan difference = model.End.Subtract(model.Begining);
                    TimeSpan timelimit;
                    int day = model.Resource.TimeLimit / 24 ?? 0;
                    int hour = model.Resource.TimeLimit % 24 ?? 0;
                    timelimit = new TimeSpan(day, hour, 0, 0);
                    if (difference > timelimit)
                    {
                        ModelState.AddModelError("", "Túl lépted az idő limitet!");
                        return View(new ReservationCreateViewModel() { Reservation = model, Resources = resourceRepo.GetResouces().ToList().ToList() });
                    }
                }

                if (model.Begining > DateTime.Now.AddHours(-1) && model.Begining < DateTime.Now)
                {
                    ModelState.AddModelError("", "Legalább egy órával a kezdés előtt le kell foglalnod!");
                    return View(new ReservationCreateViewModel() { Reservation = model, Resources = resourceRepo.GetResouces().ToList() });
                }
                if (model.Begining >= model.End)
                {
                    ModelState.AddModelError("", "A kezdő időpont nem lehet hamarabb mint a befejező!");
                    return View(new ReservationCreateViewModel() { Reservation = model, Resources = resourceRepo.GetResouces().ToList() });
                }

                var data = reservRepo.GetReservations().ToList();
                foreach (var item in data)
                {
                    if (item.ResourceId == model.ResourceId)
                    {
                        if (item.Begining < model.End && item.End > model.Begining)
                        {
                            ModelState.AddModelError("", "Ez az időpont már foglalt");
                            return View(new ReservationCreateViewModel() { Reservation = model, Resources = resourceRepo.GetResouces().ToList() });
                        }
                    }
                }

                reservRepo.InsertReservation(model);
                statRepo.InsertStatistic(new StatisticModel()
                {
                    ReservationId = model.Id,
                    ResourceId = model.ResourceId,
                    UserId = User.Identity.GetUserId(),
                    StatisticType = StatisticType.Reserv,
                    DateTime = DateTime.Now
                });
                log.Info("Új Foglalás: " + model.ToString());

                //Értesítés küldés
                var users = model.Resource.Users.Select(k => k.UserName).ToList();
                string message = string.Format("{0} lefoglalta {1} erőforrást {2} tól {3}-ig.", User.Identity.Name, model.Resource.Name, model.Begining, model.End);
                string url = "/Reservations/Details/" + model.Id;
                NotificationHelper.Send(users, "Foglalás", message, model.Resource.ImagePath, url);
                return RedirectToAction("Details", "Reservations", new { Id = model.Id });
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        public ActionResult Edit(int? id)
        {
            try
            {
                if (id == null)
                {
                    log.Warn("BadRequest");
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }
                Reservation reservation = reservRepo.GetReservationByID((int)id);
                if (reservation == null)
                {
                    log.Warn("HttpNotFound");
                    return HttpNotFound();
                }
                if (!((reservation.User == User.Identity.Name) || User.IsInRole("Admin")))
                {
                    log.Warn("Jogosultság hiba: " + User.Identity.Name);
                    return View("PermissionError");
                }
                return View(reservation);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(Reservation reservation)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    if (!((reservation.User == User.Identity.Name) || User.IsInRole("Admin")))
                    {
                        log.Warn("Jogosultsági hiba: " + User.Identity.Name);
                        return View("PermissionError");
                    }
                    var resource = resourceRepo.GetResourceByID(reservation.ResourceId);
                    if (resource.TimeLimit != null)
                    {
                        TimeSpan difference = reservation.End.Subtract(reservation.Begining);
                        TimeSpan timelimit;
                        int day = resource.TimeLimit / 24 ?? 0;
                        int hour = resource.TimeLimit % 24 ?? 0;
                        timelimit = new TimeSpan(day, hour, 0, 0);
                        if (difference > timelimit)
                        {
                            ModelState.AddModelError("", "Túl lépted az idő limitet!");
                            return View(reservation);
                        }
                    }
                    if (reservation.Begining >= reservation.End)
                    {
                        ModelState.AddModelError("", "A kezdő időpont nem lehet hamarabb mint a befejező!");
                        return View(reservation);
                    }

                    var data = reservRepo.GetReservations();
                    foreach (var item in data)
                    {
                        if (item.ResourceId == reservation.ResourceId)
                        {
                            if (item.Begining < reservation.End && item.End > reservation.Begining)
                            {
                                if (item.Id != reservation.Id)
                                {
                                    ModelState.AddModelError("", "Ez az időpont már foglalt");
                                    return View(reservation);
                                }
                            }
                        }

                    }

                    var r = reservRepo.GetReservationByID(reservation.Id);
                    r.Begining = reservation.Begining;
                    r.End = reservation.End;

                    statRepo.InsertStatistic(new StatisticModel()
                    {
                        ReservationId = r.Id,
                        ResourceId = r.ResourceId,
                        UserId = User.Identity.GetUserId(),
                        StatisticType = StatisticType.ReservartionModified,
                        DateTime = DateTime.Now
                    });
                    log.Info("Új foglalás: " + r.ToString());
              
                    //Értesítés küldés
                    var users = resource.Users.Select(k => k.UserName).ToList();
                    string message = string.Format("{0} módosította {1} erőforrás foglalását {2} tól {3}-ig.", User.Identity.Name, resource.Name, reservation.Begining, reservation.End);
                    string url = "/Reservations/Details/" + reservation.Id;
                    NotificationHelper.Send(users, "Foglalás módosítás", message, resource.ImagePath, url);
                    return RedirectToAction("Details", "Reservations", new { Id = reservation.Id });
                }
                catch (Exception ex)
                {
                    log.Error("", ex);
                    return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
                }
            }
            return View(reservation);
        }

        public ActionResult Delete(int? id)
        {
            try
            {
                if (id == null)
                {
                    log.Warn("BadRequest");
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }
                Reservation reservation = reservRepo.GetReservationByID((int)id);
                if (!((reservation.User == User.Identity.Name) || User.IsInRole("Admin")))
                {
                    log.Warn("Jogosultsági hiba: " + User.Identity.Name);
                    return View("PermissionError");
                }
                if (reservation == null)
                {
                    log.Warn("HttpNotFound");
                    return HttpNotFound();
                }
                return View(reservation);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            try
            {
                var reservation = reservRepo.GetReservationByID(id);
                if (!((reservation.User == User.Identity.Name) || User.IsInRole("Admin")))
                {
                    log.Warn("Jogosultsági hiba: " + User.Identity.Name);
                    return View("PermissionError");
                }
                //Értesítés küldés
                var users = reservation.Resource.Users.Select(k => k.UserName).ToList();
                string message = string.Format("{0} törölte {1} foglalását {2} tól {3}-ig.", User.Identity.Name, reservation.Resource.Name, reservation.Begining, reservation.End);
                NotificationHelper.Send(users, "Foglalás törlés", message, reservation.Resource.ImagePath, null);

                reservRepo.DeleteReservation(reservation.Id);
                statRepo.InsertStatistic(new StatisticModel()
                {
                    ReservationId = reservation.Id,
                    ResourceId = reservation.ResourceId,
                    UserId = User.Identity.GetUserId(),
                    StatisticType = StatisticType.ReservationDelete,
                    DateTime = DateTime.Now
                });
                log.Info("Foglalás törölve id: " + id);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }

            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                context.Dispose();
                reservRepo.Dispose();
                resourceRepo.Dispose();
                statRepo.Dispose();
                userRepo.Dispose();
            }
            base.Dispose(disposing);
        }

    }
}
