using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using isn.Data;
using isn.Entities;
using isn.Data.ApiKeys;


namespace isn.Controllers
{
    [Authorize]
    public class ApiKeysController : Controller
    {
        private readonly ApplicationDbContext dbContext;
        private readonly NugetSettings nugetSettings;
        private readonly UserManager<ApplicationUser> _userManager;

        private readonly IDataProtector protector;
        public ApiKeysController(ApplicationDbContext dbContext, 
        IOptions<NugetSettings> nugetSettingsOptions,
        IDataProtectionProvider provider,
        UserManager<ApplicationUser> userManager)
        {
            this.dbContext = dbContext;
            this.nugetSettings = nugetSettingsOptions.Value;
            protector = provider.CreateProtector(nugetSettings.ProtectionTitle);
            _userManager = userManager;
        }

        [HttpGet]
        public async Task<ActionResult> Index()
        {
            List<ApiKey> index = await GetUserKeys().ToListAsync();
            IndexModel model = new IndexModel { ApiKey = index };
            ViewData["Title"] = "Index";
            return View("Index", model);
        }

        [HttpGet]
        public async Task<ActionResult> Create()
        {
            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
            var user = await _userManager.FindByIdAsync(userId);
            ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
            return View(new CreateModel{ });
        }

        [HttpPost]
        public async Task<ActionResult> Create(CreateModel model)
        {
            string userid =  User.FindFirstValue(ClaimTypes.NameIdentifier);
            IQueryable<ApiKey> userKeys = GetUserKeys();
            if (userKeys.Count() >= nugetSettings.MaxUserKeyCount)
            {
                ModelState.AddModelError(null, "Maximum key count reached");
                return View();
            }
            ApiKey newKey = new ApiKey { UserId = userid, Name = model.Name,
            CreationDate = DateTime.Now };
            _ = dbContext.ApiKeys.Add(newKey);
            _ = await dbContext.SaveChangesAsync();
            return View("Details", new DetailModel { Name = newKey.Name,
             ProtectedValue = protector.Protect(newKey.Id),
             ApiKey = newKey });
        }

        [HttpGet]
        public async Task<ActionResult> Delete(string id)
        {
            string userid =  User.FindFirstValue(ClaimTypes.NameIdentifier);
            ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
            return View(new DeleteModel { ApiKey = key });

        }

        [HttpPost]
        public async Task<ActionResult> Delete(DeleteModel model)
        {
            string userid =  User.FindFirstValue(ClaimTypes.NameIdentifier);
            ApiKey key = dbContext.ApiKeys.FirstOrDefault(k => k.Id == model.ApiKey.Id && k.UserId == userid);
            if (key == null)
            {
                ModelState.AddModelError(null, "Key not found");
                return View();
            }
            _ = dbContext.ApiKeys.Remove(key);
            _ = await dbContext.SaveChangesAsync();
            return View("Index", new IndexModel { ApiKey = GetUserKeys().ToList() } );
        }

        public async Task<ActionResult> Details(string id)
        {
            string userid =  User.FindFirstValue(ClaimTypes.NameIdentifier);
            ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
                    if (key == null)
                    {
                        ModelState.AddModelError(null, "Key not found");
                        return View();
                    }
                    return View("Details", new DetailModel { ApiKey = key, Name = key.Name, ProtectedValue = protector.Protect(key.Id)});

        }

        public async Task<ActionResult> Edit(string id)
        {

            EditModel edit = new EditModel();
            string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
            
            var user = await _userManager.FindByIdAsync(userId);

            edit.ApiKey = await GetUserKeys().SingleOrDefaultAsync(k => 
            k.UserId == userId && k.Id == id);
            ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
         
            return View(edit);
        }

        [HttpPost]
        public async Task<ActionResult> Edit(EditModel model)
        {
            string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
            
            var apiKey = await dbContext.ApiKeys.SingleOrDefaultAsync(k => k.UserId == userId && k.Id == model.ApiKey.Id);
            apiKey.Name = model.ApiKey.Name;
            apiKey.ValidityPeriodInDays = model.ApiKey.ValidityPeriodInDays;
            await dbContext.SaveChangesAsync();
            return View("Details", new DetailModel { ApiKey = apiKey });
        }

        public IQueryable<ApiKey> GetUserKeys()
        {
            return dbContext.ApiKeys.Include(k => k.User).Where(k => k.User.UserName == User.Identity.Name);
        }
    }
}