using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using System.IO;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Data;

using Web.Models.Base;

using Model.Entities.Files;
using Model.Entities.Files.FS_Entities;
using Model.UnitsOfWork;
using Model.ViewModel.Files;
using Model.Entities.Users;

using BLL.Services;
using BLL.Services.Mapper;
using BLL.Services.FS;
using BLL;


namespace Web.Controllers.API
{
    class ViewModelItems : BaseApiResult
    {

        /// <summary>
        /// ID родительской папки
        /// </summary>
        public int ParentID { set; get; }

        /// <summary>
        /// Имя подительской папки
        /// </summary>
        public string ParentName { set; get; }

        /// <summary>
        /// Сегменты пути к текуйще папке (для переходов к родительским папкам
        /// </summary>
        public List<PathItem> Path { set; get; }

        /// <summary>
        /// ID текущей папки
        /// </summary>
        public int CurrentID { set; get; }        

        /// <summary>
        /// UI
        /// </summary>
        public bool CanWrite { set; get; }

        /// <summary>
        /// Содержимое текущей папки
        /// </summary>
        public List<ExplorerItem> items { set; get; }


        public ViewModelItems(
            Base.BaseController controller, 
            bool Successe, 
            string ResMessage
            )
            : base(
                  controller,
                  Successe,
                  ResMessage
                  ) 
        { }

    }    

    public class DeleteResult : BaseApiResult
    {
        public DeleteResult(Base.BaseController controller, bool Successe, string ResMessage)
             : base(controller, Successe, ResMessage) { }
    }

    public class CreateTmpLinkResult 
        : BaseApiResult
    {
        public string Key { set; get; }

        public CreateTmpLinkResult(
           Base.BaseController controller,
           bool Successe,
           string ResMessage
           )
           : base(
                 controller,
                 Successe,
                 ResMessage
                 )
        { }

    }

    public class ExplorerController : Base.BaseApiController
    {
        private readonly ExplorerMapper ExplorerMapper;
        private readonly LinkStorage LinkStorage;


        public ExplorerController()
        {
            ExplorerMapper = new ExplorerMapper(UOW, permissionServices, CurrentUserFunc);
            LinkStorage = new LinkStorage();
        }


        [HttpGet]
        public JsonResult GetDirectoryItems(int ID)
        {
            if (ID == -1)
            {
                //#Data #Permission
                //Выбрать корренные папки, к которым имеет доступ текущий пользователь
                //var data = UOW.Repo_SRootDirectory.All_NoTrack_List.
                //    Where(e => permissionServices.CanOpen(CurrentUser, e)).ToList();

                return new ViewModelItems(this, true, "")
                {
                    ParentID = -1,
                    ParentName = "Корень",
                    CurrentID = ID,
                    CanWrite = false,

                    Path = ExplorerMapper.GetPath(ID),
                    items = ExplorerMapper.GetDirectoryItems(ID)
                }.ToJson;
            }
            else
            {
                //#Data
                var directory = UOW
                    .Repo_SDirectory
                    .All_NoTrack
                    .Where(
                        e => e.ID == ID
                        )
                    .First();

                //#Permission
                if (!permissionServices.CanOpen(CurrentUser, directory))
                {
                    return new ViewModelItems(this, false, "CanOpen permission error")
                    {
                        PermissionError = true,
                        Path = PathItem.GetPermissionError(directory.ID),
                        items = new List<ExplorerItem>()
                    }.ToJson;
                }                

                return new ViewModelItems(this, true, "")
                {
                    ParentID = directory.IsRoot ? -1 : directory.Parent_ID.Value,
                    ParentName = directory.IsRoot ? "Корень" : directory.Parent.Name,
                    CanWrite = 
                    //false, 
                    permissionServices.CanUpload(CurrentUser, directory),

                    Path = ExplorerMapper.GetPath(ID),
                    items = ExplorerMapper.GetDirectoryItems(ID)
                }.ToJson;
            }
        }


        [HttpGet]
        public FileResult GetFile(int ID)
        {
            //#Data
            var file = UOW.Repo_SFile.All_NoTrack.
                FirstOrDefault(e => e.ID == ID);

            //#Permission
            if (!permissionServices.CanDownload(CurrentUser, file.Root))
            {
                return File(
                    new MemoryStream(), 
                    "application/octet-stream", 
                    "CanDownload permission error"
                    );
            }


            return File(
                file.Info.Open(FileMode.Open, FileAccess.Read), 
                "application/octet-stream", 
                file.Name
                );
        }


        [HttpGet]
        public JsonResult CreateOneLink(int ID)
        {
            //#Data
            var file = UOW
                .Repo_SFile
                .All_NoTrack
                .FirstOrDefault(e => e.ID == ID);

            //#Permission
            if (!permissionServices.CanDownload(CurrentUser, file.Root))
            {
                MemoryStream res = new MemoryStream();


                return
                    new CreateTmpLinkResult(this, false, "Ошибка доступа к файлу")
                    {
                        ActionName = "CreateOneLink"
                    }
                    .ToJson;
            }

            var key = LinkStorage
                .CreateTmpLink(file);

            return
                new CreateTmpLinkResult(this, true, "")
                {
                    ActionName = "CreateOneLink",
                    Key = key
                }
                .ToJson;
        }

        [HttpGet]
        public FileResult GetFileOneLink()
        {
            try
            {
                string key = Request
                    .Url
                    .OriginalString
                    .Split('/')
                    .Last();

                var file = LinkStorage
                    .GetLinkByKey(key);

                return File(
                    file.Info.Open(FileMode.Open, FileAccess.Read),
                    "application/octet-stream",
                    file.Name
                );
            }
            catch (Exception ex)
            {
                return File(
                    new MemoryStream(),
                    "application/octet-stream",
                    ex.Message + ".txt"
                    );
            }

        }




        [HttpPost]
        public JsonResult DeleteFile(int ID)
        {
            //try
            //{
            //#Data
            var file = UOW.FS_Items.FirstOrDefault(e => e.ID == ID);

            //#Permission
            if (!permissionServices.CanUpload(CurrentUser, file.Root))
            {
                return new ViewModelItems(this, false, "CanOpen permission error")
                {
                    PermissionError = true
                }.ToJson;
            }

            UOW.Delete(file);
            //}
            //catch (Exception ex)
            //{
            //var json_err = new DeleteResult(false, ex.Message);

            //return Json(json_err, JsonRequestBehavior.AllowGet);
            // }

            return new DeleteResult(this, true, "").ToJson;
        }



        [HttpGet]
        public async Task<JsonResult> ScanDirectory(int ID)
        {
            if (ID == -1)
            {
                var dir = UOW.Repo_SRootDirectory.All_List;
                new ConfigurationServices(UOW, ConfigTools).
                    ReadConfiguration();
                await new ScanServices(UOW).ScanAllDirs();
            }
            else
            {
                var dir = UOW.Repo_SDirectory.All.
                    FirstOrDefault(e => e.ID == ID);
                await new ScanServices(UOW).
                    RecursScanDirectoryAsync(dir, false);


                //var items = UOW.context.FS_Items.
                //    FirstOrDefault(e => e.ID == ID).Items.ToList();
            }

            return new BaseApiResult(this, true, "").ToJson;
        }



        [HttpPost]
        public JsonResult MoveElement(int ID, int NewParent)
        {
            //Перемещаемый элемент
            var elem = UOW.FS_Items.FirstOrDefault(e => e.ID == ID);
            //Папка в которую будет выполняться перемещение
            var new_parent = UOW.Repo_SDirectory.All.FirstOrDefault(e => e.ID == NewParent);


            if (!permissionServices.CanUpload(CurrentUser, elem.Parent) ||
                !permissionServices.CanUpload(CurrentUser, new_parent))
            {
                return new BaseApiResult(this, false, "").ToJson;
            }

            elem.Parent = new_parent;
            UOW.Update(elem);

            return new BaseApiResult(this, true, "").ToJson;
        }

        [HttpPost]
        public JsonResult CreateDirectory(int ParentID, string Name)
        {
            //#Data
            var parent = UOW.Repo_SDirectory.All.
                FirstOrDefault(e => e.ID == ParentID);

            //#Permission
            if (!permissionServices.CanUpload(CurrentUser, parent))
            {
                return new BaseApiResult(this, false, "").ToJson;
            }

            UOW.Repo_SDirectory.
                Create(new SDirectory((SDirectory)parent, Name, CurrentUser));

            return new BaseApiResult(this, true, "").ToJson;
        }

    }

}