using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NuGet.Versioning;
using isn.Data;
using isn.Entities;
using Unleash.ClientFactory;
using Unleash;
using System.Collections.Generic;
using isnd.Services;
using isnd.Entities;
using Microsoft.AspNetCore.Hosting;
using isnd.Helpers;

namespace isn.Controllers
{

    [AllowAnonymous]
    public partial class PackagesController : Controller
    {
        const int maxTake = 100;

        const string _pkgRootPrefix = "~/package";
        const string defaultSemVer = "2.0.0";
        private readonly Resource[] ressources;
        private readonly ILogger<PackagesController> logger;
        private readonly IDataProtector protector;

        private readonly NugetSettings nugetSettings;
        readonly ApplicationDbContext dbContext;
        private readonly PackageManager packageManager;
        private readonly IUnleash _unleashĈlient;

        public PackagesController(
            PackageManager packageManager,
            ILoggerFactory loggerFactory,
            IDataProtectionProvider provider,
            IOptions<NugetSettings> nugetOptions,
            IOptions<UnleashClientSettings> unleashClientSettings,
            IHostingEnvironment env,
            ApplicationDbContext dbContext)
        {
            logger = loggerFactory.CreateLogger<PackagesController>();
            nugetSettings = nugetOptions.Value;
            protector = provider.CreateProtector(nugetSettings.ProtectionTitle);
            this.dbContext = dbContext;
            this.packageManager = packageManager;
            _unleashĈlient = env.CreateUnleahClient(unleashClientSettings.Value);
            ressources = packageManager.GetResources(_unleashĈlient).ToArray();
        }

        // dotnet add . package -s http://localhost:5000/packages isn
        // packages/FindPackagesById()?id='isn'&semVerLevel=2.0.0

        // Search
        // GET {@id}?q={QUERY}&skip={SKIP}&take={TAKE}&prerelease={PRERELEASE}&semVerLevel={SEMVERLEVEL}&packageType={PACKAGETYPE}


        [HttpGet("~/index.json")]
        public IActionResult ApiIndex()
        {
            return Ok(ressources);
        }


        [HttpGet(_pkgRootPrefix + "/index.json")]
        public IActionResult Index(
            string q,
            string semVerLevel,
            bool prerelease = false,
            string packageType = null,
            int skip = 0,
            int take = 25)
        {
            if (string.IsNullOrEmpty(q))
            {
                ModelState.AddModelError("q", "no value");
            }
            if (take > maxTake)
            {
                ModelState.AddModelError("take", "Maximum exceeded");
            }
            if (semVerLevel != defaultSemVer)
            {
                ModelState.AddModelError("semVerLevel", defaultSemVer + " expected");
            }
            if (ModelState.IsValid)
            {
                return Ok(packageManager.SearchByName(q,skip,take,prerelease,packageType));
            }
            return BadRequest(new { error = ModelState });
        }

        // GET /autocomplete?id=nuget.protocol&prerelease=true
        [HttpGet(_pkgRootPrefix + "/autocomplete")]
        public IActionResult AutoComplete(
            string id,
            string semVerLevel,
            bool prerelease = false,
            string packageType = null,
            int skip = 0,
            int take = 25)
        {
            if (take > maxTake)
            {
                ModelState.AddModelError("take", "Maximum exceeded");
                return BadRequest(ModelState);
            }
            if (semVerLevel != defaultSemVer)
            {
                ModelState.AddModelError("semVerLevel", defaultSemVer + " expected");
            }
            
            return Ok(packageManager.AutoComplete(id,skip,take,prerelease,packageType));
        }
        // TODO GET {@id}/{LOWER_ID}/index.json 
        // LOWER_ID 	URL 	string 	yes 	The package ID, lowercased
        // response : versions 	array of strings 	yes 	The versions available
        [HttpGet(_pkgRootPrefix + "/{id}/{lower}/index.json")]
        public IActionResult GetVersions(
            string id,
            string lower,
            bool prerelease = false,
            string packageType = null,
            int skip = 0,
            int take = 25)
        {
            if (take > maxTake)
            {
                ModelState.AddModelError("take", "Maximum exceeded");
            }
            // NugetVersion
            if (!NuGetVersion.TryParse(lower, out NuGetVersion parsedVersion))
            {
                ModelState.AddModelError("lower", "invalid version string");
            }
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            return Ok(new
            {
                versions = packageManager.GetVersions(
                    id, parsedVersion, prerelease, packageType, skip, take)
            });
        }

        // TODO GET GET {@id}/{LOWER_ID}/{LOWER_VERSION}/{LOWER_ID}.{LOWER_VERSION}.nupkg
        // LOWER_ID 	URL 	string 	yes 	The package ID, lowercase
        // LOWER_VERSION 	URL 	string 	yes 	The package version, normalized and lowercased
        // response 200 : the package
        [HttpGet(_pkgRootPrefix + "/{id}/{lower}/{idf}.{lowerf}.nupkg")]
        public IActionResult GetPackage(
           [FromRoute] string id, [FromRoute] string lower,
            [FromRoute] string idf, [FromRoute] string lowerf)
        {
            var pkgpath = Path.Combine(nugetSettings.PackagesRootDir,
            id, lower, $"{idf}.{lowerf}.nupkg"
            );

            FileInfo pkgfi = new FileInfo(pkgpath);
            return File(pkgfi.OpenRead(), "application/zip; charset=binary");
        }

        // TODO GET {@id}/{LOWER_ID}/{LOWER_VERSION}/{LOWER_ID}.nuspec
        // response 200 : the nuspec
        [HttpGet(_pkgRootPrefix + "/{id}/{lower}/{idf}.{lowerf}.nuspec")]
        public IActionResult GetNuspec(
            [FromRoute][SafeName][Required] string id,
            [FromRoute][SafeName][Required] string lower,
            [FromRoute][SafeName][Required] string idf,
            [FromRoute][SafeName][Required] string lowerf)
        {
            var pkgpath = Path.Combine(nugetSettings.PackagesRootDir,
            id, lower, $"{idf}.{lowerf}.nuspec");

            FileInfo pkgfi = new FileInfo(pkgpath);
            return File(pkgfi.OpenRead(), "text/xml; charset=utf-8");
        }
    }
}