using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Net.Http.Headers;
using WinSCP;

namespace WebApi
{
    [RoutePrefix("api/craftfile")]
    public class CraftFileController : ApiController
    {
        // 本地缓存根目录
        private readonly string _cacheRoot = @"D:\\CraftFilesCache";

        private readonly string _sftpHost = "10.107.69.5";
        private readonly string _sftpUser = "root";
        private readonly string _sftpPassword = "XKYXmes@123!";

        public class FileRequestDto
        {
            // 远程（SFTP）相对路径或绝对路径：如 /root/PLM-MES/.../xxx.pdf
            public string RelativePath { get; set; } = "";
        }

        [HttpPost]
        [Route("browse")]
        public IHttpActionResult Browse([FromBody] FileRequestDto request)
        {
            try
            {
                if (request == null || string.IsNullOrWhiteSpace(request.RelativePath))
                    return Ok(new { success = false, message = "路径不能为空" });

                EnsureCacheRoot();

                var remotePath = NormalizeRemotePath(request.RelativePath);
                var localPath = ToLocalPath(remotePath);

                var isFile = Path.HasExtension(remotePath);

                if (isFile)
                {
                    // 确保本地存在
                    if (!System.IO.File.Exists(localPath))
                    {
                        var ok = DownloadFileFromSftp(remotePath, localPath, out string err);
                        if (!ok) return Ok(new { success = false, message = $"下载失败: {err}" });
                    }
                    return GetFilePreviewLocal(localPath, remotePath);
                }
                else
                {
                    // 目录：优先读取本地，没有则读取远程目录结构
                    if (Directory.Exists(localPath))
                    {
                        return GetDirectoryContentsLocal(localPath, remotePath);
                    }
                    else
                    {
                        return GetDirectoryContentsRemote(remotePath);
                    }
                }
            }
            catch (Exception ex)
            {
                return Ok(new { success = false, message = $"服务器错误: {ex.Message}" });
            }
        }

        [HttpPost]
        [Route("download")]
        public IHttpActionResult Download([FromBody] FileRequestDto request)
        {
            try
            {
                if (request == null || string.IsNullOrWhiteSpace(request.RelativePath))
                    return Ok(new { success = false, message = "文件路径不能为空" });

                EnsureCacheRoot();

                var remotePath = NormalizeRemotePath(request.RelativePath);
                var localPath = ToLocalPath(remotePath);

                if (!Path.HasExtension(remotePath))
                    return Ok(new { success = false, message = "请传入文件路径" });

                if (!System.IO.File.Exists(localPath))
                {
                    var ok = DownloadFileFromSftp(remotePath, localPath, out string err);
                    if (!ok) return Ok(new { success = false, message = $"下载失败: {err}" });
                }

                var fileInfo = new FileInfo(localPath);
                var contentType = GetContentType(fileInfo.Name);
                var response = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StreamContent(new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                };
                response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
                response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                {
                    FileName = fileInfo.Name
                };
                return ResponseMessage(response);
            }
            catch (Exception ex)
            {
                return Ok(new { success = false, message = $"下载文件失败: {ex.Message}" });
            }
        }

        // 新增：浏览器直接预览文件（支持PDF等），支持Range分块
        [HttpGet]
        [Route("preview")]
        public HttpResponseMessage Preview([FromUri] string path)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(path))
                {
                    return Request.CreateResponse(HttpStatusCode.BadRequest, new { success = false, message = "文件路径不能为空" });
                }

                EnsureCacheRoot();
                var remotePath = NormalizeRemotePath(path);
                var localPath = ToLocalPath(remotePath);

                if (!Path.HasExtension(remotePath))
                {
                    return Request.CreateResponse(HttpStatusCode.BadRequest, new { success = false, message = "请传入文件路径" });
                }

                if (!System.IO.File.Exists(localPath))
                {
                    var ok = DownloadFileFromSftp(remotePath, localPath, out string err);
                    if (!ok)
                    {
                        return Request.CreateResponse(HttpStatusCode.InternalServerError, new { success = false, message = $"下载失败: {err}" });
                    }
                }

                var fileInfo = new FileInfo(localPath);
                var contentType = GetContentType(fileInfo.Name);
                var totalLength = fileInfo.Length;

                var response = new HttpResponseMessage();
                var range = Request.Headers.Range;

                var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read);
                if (range != null && range.Ranges.Count > 0 && totalLength > 0)
                {
                    // 处理 Range 请求
                    var from = range.Ranges.First().From ?? 0;
                    var to = range.Ranges.First().To ?? (totalLength - 1);
                    if (to >= totalLength) to = totalLength - 1;
                    var length = to - from + 1;
                    stream.Seek(from, SeekOrigin.Begin);

                    response.StatusCode = HttpStatusCode.PartialContent;
                    response.Content = new StreamContent(stream);
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
                    response.Content.Headers.ContentLength = length;
                    response.Content.Headers.ContentRange = new ContentRangeHeaderValue(from, to, totalLength);
                    response.Headers.AcceptRanges.Add("bytes");
                }
                else
                {
                    // 全量流式
                    response.StatusCode = HttpStatusCode.OK;
                    response.Content = new StreamContent(stream);
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
                    response.Content.Headers.ContentLength = totalLength;
                    response.Headers.AcceptRanges.Add("bytes");
                }

                // inline 以支持浏览器内嵌预览
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
                {
                    FileName = fileInfo.Name
                };

                // CORS 允许跨域及暴露必要头
                if (!response.Headers.Contains("Access-Control-Allow-Origin"))
                    response.Headers.Add("Access-Control-Allow-Origin", "*");
                if (!response.Headers.Contains("Access-Control-Expose-Headers"))
                    response.Headers.Add("Access-Control-Expose-Headers", "Accept-Ranges, Content-Range, Content-Length, Content-Type, Content-Disposition");

                return response;
            }
            catch (Exception ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, new { success = false, message = $"预览失败: {ex.Message}" });
            }
        }

        private IHttpActionResult GetFilePreviewLocal(string localPath, string remotePath)
        {
            try
            {
                var fileInfo = new FileInfo(localPath);
                var extension = fileInfo.Extension.ToLowerInvariant();
                var previewable = IsPreviewableFile(extension);
                var contentType = GetContentType(fileInfo.Name);

                bool tooLarge = fileInfo.Length > 500 * 1024 * 1024; // 500MB限制
                string base64String = null;
                string dataUrl = null;
                bool canPreview = previewable && !tooLarge;
                if (canPreview)
                {
                    var fileBytes = System.IO.File.ReadAllBytes(localPath);
                    base64String = Convert.ToBase64String(fileBytes);
                    dataUrl = $"data:{contentType};base64,{base64String}";
                }

                var result = new
                {
                    success = true,
                    type = "file",
                    path = remotePath,
                    name = fileInfo.Name,
                    size = fileInfo.Length,
                    extension = fileInfo.Extension,
                    contentType = contentType,
                    isPreviewable = canPreview,
                    base64Data = base64String,
                    dataUrl = dataUrl,
                    created = fileInfo.CreationTime,
                    modified = fileInfo.LastWriteTime,
                    message = tooLarge ? "文件过大，无法预览，可下载" : null
                };
                return Ok(result);
            }
            catch (Exception ex)
            {
                return Ok(new { success = false, message = $"获取文件预览失败: {ex.Message}" });
            }
        }

        private IHttpActionResult GetDirectoryContentsLocal(string localPath, string remotePath)
        {
            try
            {
                var items = new List<object>();
                var directories = Directory.GetDirectories(localPath);
                foreach (var dir in directories)
                {
                    var dirInfo = new DirectoryInfo(dir);
                    var subPath = CombineRemotePath(remotePath, dirInfo.Name);
                    items.Add(new
                    {
                        name = dirInfo.Name,
                        type = "directory",
                        path = subPath,
                        created = dirInfo.CreationTime,
                        modified = dirInfo.LastWriteTime,
                        isPreviewable = false
                    });
                }
                var files = Directory.GetFiles(localPath);
                foreach (var file in files)
                {
                    var fileInfo = new FileInfo(file);
                    var filePath = CombineRemotePath(remotePath, fileInfo.Name);
                    var extension = fileInfo.Extension.ToLowerInvariant();
                    items.Add(new
                    {
                        name = fileInfo.Name,
                        type = "file",
                        path = filePath,
                        size = fileInfo.Length,
                        extension = fileInfo.Extension,
                        created = fileInfo.CreationTime,
                        modified = fileInfo.LastWriteTime,
                        isPreviewable = IsPreviewableFile(extension),
                        contentType = GetContentType(fileInfo.Name)
                    });
                }
                var result = new
                {
                    success = true,
                    type = "directory",
                    path = remotePath,
                    items = items.OrderBy(x => ((dynamic)x).type == "directory" ? 0 : 1)
                           .ThenBy(x => ((dynamic)x).name)
                           .ToList()
                };
                return Ok(result);
            }
            catch (Exception ex)
            {
                return Ok(new { success = false, message = $"读取目录失败: {ex.Message}" });
            }
        }

        private IHttpActionResult GetDirectoryContentsRemote(string remotePath)
        {
            try
            {
                using (var session = OpenSftp())
                {
                    var dir = session.ListDirectory(remotePath);
                    var items = new List<object>();

                    foreach (var subdir in dir.Files.Where(e => e.IsDirectory && e.Name != "." && e.Name != ".."))
                    {
                        var subPath = CombineRemotePath(remotePath, subdir.Name);
                        items.Add(new
                        {
                            name = subdir.Name,
                            type = "directory",
                            path = subPath,
                            created = subdir.LastWriteTime,
                            modified = subdir.LastWriteTime,
                            isPreviewable = false
                        });
                    }

                    foreach (var file in dir.Files.Where(e => !e.IsDirectory))
                    {
                        var filePath = CombineRemotePath(remotePath, file.Name);
                        var extension = Path.GetExtension(file.Name).ToLowerInvariant();
                        items.Add(new
                        {
                            name = file.Name,
                            type = "file",
                            path = filePath,
                            size = file.Length,
                            extension = Path.GetExtension(file.Name),
                            created = file.LastWriteTime,
                            modified = file.LastWriteTime,
                            isPreviewable = IsPreviewableFile(extension),
                            contentType = GetContentType(file.Name)
                        });
                    }

                    var result = new
                    {
                        success = true,
                        type = "directory",
                        path = remotePath,
                        items = items.OrderBy(x => ((dynamic)x).type == "directory" ? 0 : 1)
                               .ThenBy(x => ((dynamic)x).name)
                               .ToList()
                    };
                    return Ok(result);
                }
            }
            catch (Exception ex)
            {
                return Ok(new { success = false, message = $"读取远程目录失败: {ex.Message}" });
            }
        }

        private bool DownloadFileFromSftp(string remotePath, string localPath, out string error)
        {
            error = null;
            try
            {
                var localDir = Path.GetDirectoryName(localPath);
                if (!Directory.Exists(localDir)) Directory.CreateDirectory(localDir);

                using (var session = OpenSftp())
                {
                    var result = session.GetFiles(remotePath, localPath, false);
                    result.Check();
                }
                return true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
                return false;
            }
        }

        private Session OpenSftp()
        {
            var options = new SessionOptions
            {
                Protocol = Protocol.Sftp,
                HostName = _sftpHost,
                UserName = _sftpUser,
                Password = _sftpPassword,
                SshHostKeyPolicy = SshHostKeyPolicy.GiveUpSecurityAndAcceptAny
            };
            var session = new Session();
            session.Open(options);
            return session;
        }

        private void EnsureCacheRoot()
        {
            if (!Directory.Exists(_cacheRoot)) Directory.CreateDirectory(_cacheRoot);
        }

        private string NormalizeRemotePath(string p)
        {
            if (string.IsNullOrWhiteSpace(p)) return "/";
            var s = p.Trim();
            // 统一使用正斜杠
            s = s.Replace('\\', '/');
            return s;
        }

        private string ToLocalPath(string remotePath)
        {
            // 去掉开头的 '/'
            var relative = remotePath.Trim().TrimStart('/');
            var localRelative = relative.Replace('/', Path.DirectorySeparatorChar);
            return Path.Combine(_cacheRoot, localRelative);
        }

        private string CombineRemotePath(string basePath, string name)
        {
            if (string.IsNullOrEmpty(basePath) || basePath == "/") return $"/{name}";
            if (basePath.EndsWith("/")) return basePath + name;
            return basePath + "/" + name;
        }

        private bool IsPreviewableFile(string extension)
        {
            var previewableExtensions = new[]
            {
                ".bmp", ".jpg", ".jpeg", ".png", ".gif", ".tiff", ".tif", ".webp",
                ".txt", ".json", ".xml", ".csv", ".log", ".md", ".pdf"
            };
            return previewableExtensions.Contains(extension);
        }

        private string GetContentType(string fileName)
        {
            var extension = Path.GetExtension(fileName).ToLowerInvariant();
            if (extension == ".bmp") return "image/bmp";
            if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
            if (extension == ".png") return "image/png";
            if (extension == ".gif") return "image/gif";
            if (extension == ".tiff" || extension == ".tif") return "image/tiff";
            if (extension == ".webp") return "image/webp";
            if (extension == ".pdf") return "application/pdf";
            if (extension == ".txt") return "text/plain";
            if (extension == ".json") return "application/json";
            if (extension == ".xml") return "application/xml";
            if (extension == ".csv") return "text/csv";
            if (extension == ".md") return "text/markdown";
            if (extension == ".log") return "text/plain";
            if (extension == ".zip") return "application/zip";
            if (extension == ".rar") return "application/x-rar-compressed";
            return "application/octet-stream";
        }
    }
}


