private void AddRemoveTeamsProjects(ProjectSaveModel model, DataSets.Project dbProject)
        {
            // remove all items not in the model
            dbProject.TeamsProjects.RemoveAll(k => !model.teamsIds.Contains(k.TeamId));

            // remove all items in the model that are already in db
            model.teamsIds.RemoveAll(k => dbProject.TeamsProjects.Any(t => t.TeamId == k));

            // add the rest
            if (model.teamsIds.Count > 0)
            {
                dbProject.TeamsProjects.AddRange(model.teamsIds.Select(k => new DataSets.TeamsProjects()
                {
                    ProjectId = dbProject.ID,
                    TeamId    = k
                }));
            }
        }
        public async Task <IActionResult> Save([FromBody] ProjectSaveModel model)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            try
            {
                string userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;

                model.SetStatusByUserId(userId);

                return(Ok(await _projects.Save(model)));
            }
            catch (ClientException ex)
            {
                return(BadRequest(new { message = ex.Message }));
            }
            catch (Exception ex)
            {
                return(StatusCode(500, new { message = ex.Message }));
            }
        }
        public async Task <Project> Save(ProjectSaveModel model)
        {
            if (model.categoryId == 0 || string.IsNullOrEmpty(model.title))
            {
                throw new ClientException("title and category are required");
            }

            if (model.startDate.HasValue)
            {
                if (model.plannedEnd.HasValue && model.plannedEnd.Value <= model.startDate.Value)
                {
                    throw new ClientException("Planned Date must be greater than Start Date");
                }

                if (model.actualEnd.HasValue && model.actualEnd.Value <= model.startDate.Value)
                {
                    throw new ClientException("Actual Date must be greater than Start Date");
                }
            }

            if (model.id.HasValue)
            {
                // check if title already exist under the selected category
                bool nameExist = db.Projects.Any(k => k.ID != model.id.Value && k.Title == model.title && k.CategoryId == model.categoryId);

                if (nameExist)
                {
                    throw new ClientException($"project exist under title {model.title} and the selected category");
                }

                // # save project #

                // get project

                var dbProject = db.Projects
                                .Include(k => k.TeamsProjects)
                                .Include(k => k.ProjectStatusModifications)
                                .FirstOrDefault(k => k.ID == model.id.Value);

                if (dbProject == null)
                {
                    throw new ClientException("record not found");
                }

                // check if status changed
                bool statusChanged = dbProject.StatusCode != model.statusCode || dbProject.StatusByUserId != model.GetStatusByUserId();

                if (statusChanged)
                {
                    // append project's status modification
                    dbProject.ProjectStatusModifications.Add(new DataSets.ProjectStatusModification()
                    {
                        ProjectId        = dbProject.ID,
                        StatusCode       = dbProject.StatusCode,
                        DateModified     = DateTime.Now,
                        ModifiedByUserId = dbProject.StatusByUserId
                    });

                    await NotifyAdmins(model.GetStatusByUserId(), $"project status was changed", dbProject.ID);
                }

                // update values

                dbProject.Title            = model.title;
                dbProject.Description      = model.description;
                dbProject.CategoryId       = model.categoryId;
                dbProject.StartDate        = model.startDate;
                dbProject.PlannedEnd       = model.plannedEnd;
                dbProject.ActualEnd        = model.actualEnd;
                dbProject.LastModifiedDate = DateTime.Now;
                dbProject.StatusCode       = model.statusCode;
                dbProject.StatusByUserId   = model.GetStatusByUserId();

                AddRemoveTeamsProjects(model, dbProject);

                db.SaveChanges();

                return(GetById(dbProject.ID));
            }
            else
            {
                // # new task #

                // check if title already exist under the selected category
                bool nameExist = db.Projects.Any(k => k.Title == model.title && k.CategoryId == model.categoryId);

                if (nameExist)
                {
                    throw new ClientException($"project exist under title {model.title} and the selected category");
                }

                DataSets.Project dbProject = new DataSets.Project()
                {
                    Title          = model.title,
                    Description    = model.description,
                    DateAdded      = DateTime.Now,
                    CategoryId     = model.categoryId,
                    StartDate      = model.startDate,
                    PlannedEnd     = model.plannedEnd,
                    ActualEnd      = model.actualEnd,
                    StatusCode     = model.statusCode,
                    StatusByUserId = model.GetStatusByUserId(),
                    AddedByUserId  = model.GetStatusByUserId()
                };

                // add the project
                db.Projects.Add(dbProject);

                // save changes on project
                db.SaveChanges();

                // add the teams to the saved project
                db.TeamsProjects.AddRange(model.teamsIds.Select(k => new DataSets.TeamsProjects()
                {
                    ProjectId = dbProject.ID,
                    TeamId    = k
                }));

                // save changes on teamsprojects
                db.SaveChanges();

                // notify admin of new project

                await NotifyAdmins(model.GetStatusByUserId(), $"new project was added", dbProject.ID);


                return(GetById(dbProject.ID));
            }
        }