using System;
using System.Linq;
using System.Web.Security;
using MileageTraker.Web.Context;
using MileageTraker.Web.Models;

namespace MileageTraker.Web.DAL
{
	public class CodeFirstRoleProvider : RoleProvider
	{
		public override string ApplicationName
		{
			get { return GetType().Assembly.GetName().Name; }
			set
			{
				if (value == null) throw new ArgumentNullException("value");
				ApplicationName = GetType().Assembly.GetName().Name;
			}
		}

		public override bool RoleExists(string roleName)
		{
			if (string.IsNullOrEmpty(roleName))
			{
				return false;
			}
			using (var context = new MileageTrakerContext())
			{
				var role = context.Roles.FirstOrDefault(rl => rl.RoleName == roleName);
				return role != null;
			}
		}

		public override bool IsUserInRole(string username, string roleName)
		{
			if (string.IsNullOrEmpty(username))
			{
				return false;
			}
			if (string.IsNullOrEmpty(roleName))
			{
				return false;
			}
			using (var context = new MileageTrakerContext())
			{
				var user = context.Users.FirstOrDefault(usr => usr.Username == username);
				if (user == null)
				{
					return false;
				}
				var role = context.Roles.FirstOrDefault(rl => rl.RoleName == roleName);
				if (role == null)
				{
					return false;
				}
				return user.Roles.Contains(role);
			}
		}

		public override string[] GetAllRoles()
		{
			using (var context = new MileageTrakerContext())
			{
				return context.Roles.Select(rl => rl.RoleName).ToArray();
			}
		}

		public override string[] GetUsersInRole(string roleName)
		{
			if (string.IsNullOrEmpty(roleName))
			{
				return null;
			}
			using (var context = new MileageTrakerContext())
			{
				var role = context.Roles.FirstOrDefault(rl => rl.RoleName == roleName);
				if (role != null)
				{
					return role.Users.Select(usr => usr.Username).ToArray();
				}
				return null;
			}
		}

		public override string[] GetRolesForUser(string username)
		{
			if (string.IsNullOrEmpty(username))
			{
				return null;
			}
			using (var context = new MileageTrakerContext())
			{
				var user = context.Users.FirstOrDefault(usr => usr.Username == username);
				if (user != null)
				{
					return user.Roles.Select(rl => rl.RoleName).ToArray();
				}
				return null;
			}
		}

		public override string[] FindUsersInRole(string roleName, string usernameToMatch)
		{
			throw new NotSupportedException();
			if (string.IsNullOrEmpty(roleName))
			{
				return null;
			}

			if (string.IsNullOrEmpty(usernameToMatch))
			{
				return null;
			}

			using (var context = new MileageTrakerContext())
			{
				return (from rl in context.Roles
				        from usr in rl.Users
				        where rl.RoleName == roleName && usr.Username.Contains(usernameToMatch)
				        select usr.Username).ToArray();
			}
		}

		public override void CreateRole(string roleName)
		{
			throw new NotSupportedException();
			if (!string.IsNullOrEmpty(roleName))
			{
				using (var context = new MileageTrakerContext())
				{
					var role = context.Roles.FirstOrDefault(rl => rl.RoleName == roleName);
					if (role == null)
					{
						var newRole = new Role
							{
								RoleId = Guid.NewGuid(),
								RoleName = roleName
							};
						context.Roles.Add(newRole);
						context.SaveChanges();
					}
				}
			}
		}

		public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
		{
			throw new NotSupportedException();
			if (string.IsNullOrEmpty(roleName))
			{
				return false;
			}
			using (var context = new MileageTrakerContext())
			{
				var role = context.Roles.FirstOrDefault(rl => rl.RoleName == roleName);
				if (role == null)
				{
					return false;
				}
				if (throwOnPopulatedRole)
				{
					if (role.Users.Any())
					{
						return false;
					}
				}
				else
				{
					role.Users.Clear();
				}
				context.Roles.Remove(role);
				context.SaveChanges();
				return true;
			}
		}

		public override void AddUsersToRoles(string[] usernames, string[] roleNames)
		{
			using (var context = new DataService())
			{
				var users = context.GetUsers().Where(usr => usernames.Contains(usr.Username)).ToList();
				var roles = context.GetRoles().Where(rl => roleNames.Contains(rl.RoleName)).ToList();
				foreach (var user in users)
				{
					foreach (var role in roles)
					{
						if (!user.Roles.Contains(role))
						{
							user.Roles.Add(role);
						}
					}
					context.UpdateUser(user);
				}
			}
		}

		public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
		{
			using (var context = new DataService())
			{
				foreach (var username in usernames)
				{
					var us = username;
					var user = context.GetUsers().FirstOrDefault(u => u.Username == us);
					if (user != null)
					{
						foreach (var roleName in roleNames)
						{
							var rl = roleName;
							var role = user.Roles.FirstOrDefault(r => r.RoleName == rl);
							if (role != null)
							{
								user.Roles.Remove(role);
							}
						}
						context.UpdateUser(user);
					}
				}
			}
		}
	}
}