// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/fml/file.h"

#include <Fileapi.h>
#include <Shlwapi.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <string>

#include <algorithm>
#include <climits>
#include <cstring>
#include <optional>
#include <sstream>

#include "flutter/fml/build_config.h"
#include "flutter/fml/mapping.h"
#include "flutter/fml/platform/win/errors_win.h"
#include "flutter/fml/platform/win/wstring_conversion.h"

namespace fml {

static std::string GetFullHandlePath(const fml::UniqueFD& handle) {
  // Although the documentation claims that GetFinalPathNameByHandle is
  // supported for UWP apps, turns out it returns ACCESS_DENIED in this case
  // hence the need to workaround it by maintaining a map of file handles to
  // absolute paths populated by fml::OpenDirectory.
#ifdef WINUWP
  std::optional<fml::internal::os_win::DirCacheEntry> found =
      fml::internal::os_win::UniqueFDTraits::GetCacheEntry(handle.get());

  if (found) {
    FILE_ID_INFO info;

    BOOL result = GetFileInformationByHandleEx(
        handle.get(), FILE_INFO_BY_HANDLE_CLASS::FileIdInfo, &info,
        sizeof(FILE_ID_INFO));

    // Assuming it was possible to retrieve fileinfo, compare the id field.  The
    // handle hasn't been reused if the file identifier is the same as when it
    // was cached
    if (result && memcmp(found.value().id.Identifier, info.FileId.Identifier,
                         sizeof(FILE_ID_INFO))) {
      return WideStringToString(found.value().filename);
    } else {
      fml::internal::os_win::UniqueFDTraits::RemoveCacheEntry(handle.get());
    }
  }

  return std::string();
#else
  wchar_t buffer[MAX_PATH] = {0};
  const DWORD buffer_size = ::GetFinalPathNameByHandle(
      handle.get(), buffer, MAX_PATH, FILE_NAME_NORMALIZED);
  if (buffer_size == 0) {
    FML_DLOG(ERROR) << "Could not get file handle path. "
                    << GetLastErrorMessage();
    return {};
  }
  return WideStringToString({buffer, buffer_size});
#endif
}

static std::string GetAbsolutePath(const fml::UniqueFD& base_directory,
                                   const char* subpath) {
  std::stringstream stream;
  stream << GetFullHandlePath(base_directory) << "\\" << subpath;
  auto path = stream.str();
  std::replace(path.begin(), path.end(), '/', '\\');
  return path;
}

static std::wstring GetTemporaryDirectoryPath() {
  wchar_t wchar_path[MAX_PATH];
  auto result_size = ::GetTempPath(MAX_PATH, wchar_path);
  if (result_size > 0) {
    return {wchar_path, result_size};
  }
  FML_DLOG(ERROR) << "Could not get temporary directory path. "
                  << GetLastErrorMessage();
  return {};
}

static DWORD GetDesiredAccessFlags(FilePermission permission) {
  switch (permission) {
    case FilePermission::kRead:
      return GENERIC_READ;
    case FilePermission::kWrite:
      return GENERIC_WRITE;
    case FilePermission::kReadWrite:
      return GENERIC_READ | GENERIC_WRITE;
  }
  return GENERIC_READ;
}

static DWORD GetShareFlags(FilePermission permission) {
  switch (permission) {
    case FilePermission::kRead:
      return FILE_SHARE_READ;
    case FilePermission::kWrite:
      return FILE_SHARE_WRITE;
    case FilePermission::kReadWrite:
      return FILE_SHARE_READ | FILE_SHARE_WRITE;
  }
  return FILE_SHARE_READ;
}

static DWORD GetFileAttributesForUtf8Path(const char* absolute_path) {
  return ::GetFileAttributes(StringToWideString(absolute_path).c_str());
}

static DWORD GetFileAttributesForUtf8Path(const fml::UniqueFD& base_directory,
                                          const char* path) {
  std::string full_path = GetFullHandlePath(base_directory) + "\\" + path;
  return GetFileAttributesForUtf8Path(full_path.c_str());
}

std::string CreateTemporaryDirectory() {
  // Get the system temporary directory.
  auto temp_dir_container = GetTemporaryDirectoryPath();
  if (temp_dir_container.size() == 0) {
    FML_DLOG(ERROR) << "Could not get system temporary directory.";
    return {};
  }

  // Create a UUID.
  UUID uuid;
  RPC_STATUS status = UuidCreateSequential(&uuid);
  if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
    FML_DLOG(ERROR) << "Could not create UUID";
    return {};
  }

  RPC_WSTR uuid_string;
  status = UuidToString(&uuid, &uuid_string);
  if (status != RPC_S_OK) {
    FML_DLOG(ERROR) << "Could not create UUID to string.";
    return {};
  }

  std::wstring uuid_str(reinterpret_cast<wchar_t*>(uuid_string));
  RpcStringFree(&uuid_string);

  // Join the two and create a path to the new temporary directory.

  std::wstringstream stream;
  stream << temp_dir_container << "\\" << uuid_str;
  auto temp_dir = stream.str();

  auto dir_fd = OpenDirectory(WideStringToString(temp_dir).c_str(), true,
                              FilePermission::kReadWrite);
  if (!dir_fd.is_valid()) {
    FML_DLOG(ERROR) << "Could not get temporary directory FD. "
                    << GetLastErrorMessage();
    return {};
  }

  return WideStringToString(std::move(temp_dir));
}

fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory,
                       const char* path,
                       bool create_if_necessary,
                       FilePermission permission) {
  return OpenFile(GetAbsolutePath(base_directory, path).c_str(),
                  create_if_necessary, permission);
}

fml::UniqueFD OpenFile(const char* path,
                       bool create_if_necessary,
                       FilePermission permission) {
  if (path == nullptr || strlen(path) == 0) {
    return {};
  }

  auto file_name = StringToWideString({path});

  if (file_name.size() == 0) {
    return {};
  }

  const DWORD creation_disposition =
      create_if_necessary ? CREATE_NEW : OPEN_EXISTING;

  const DWORD flags = FILE_ATTRIBUTE_NORMAL;

  auto handle =
      CreateFile(file_name.c_str(),                  // lpFileName
                 GetDesiredAccessFlags(permission),  // dwDesiredAccess
                 GetShareFlags(permission),          // dwShareMode
                 nullptr,                            // lpSecurityAttributes  //
                 creation_disposition,               // dwCreationDisposition //
                 flags,   // dwFlagsAndAttributes                  //
                 nullptr  // hTemplateFile                         //
      );

  if (handle == INVALID_HANDLE_VALUE) {
    FML_DLOG(ERROR) << "Could not open file. " << GetLastErrorMessage();
    return {};
  }

  return fml::UniqueFD{handle};
}

fml::UniqueFD OpenDirectory(const fml::UniqueFD& base_directory,
                            const char* path,
                            bool create_if_necessary,
                            FilePermission permission) {
  return OpenDirectory(GetAbsolutePath(base_directory, path).c_str(),
                       create_if_necessary, permission);
}

fml::UniqueFD OpenDirectory(const char* path,
                            bool create_if_necessary,
                            FilePermission permission) {
  if (path == nullptr || strlen(path) == 0) {
    return {};
  }

  auto file_name = StringToWideString({path});

  if (file_name.size() == 0) {
    return {};
  }

  if (create_if_necessary) {
    if (!::CreateDirectory(file_name.c_str(), nullptr)) {
      if (GetLastError() != ERROR_ALREADY_EXISTS) {
        FML_DLOG(ERROR) << "Could not create directory. "
                        << GetLastErrorMessage();
        return {};
      }
    }
  }

  const DWORD creation_disposition = OPEN_EXISTING;

  const DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;

  auto handle =
      CreateFile(file_name.c_str(),                  // lpFileName
                 GetDesiredAccessFlags(permission),  // dwDesiredAccess
                 GetShareFlags(permission),          // dwShareMode
                 nullptr,                            // lpSecurityAttributes  //
                 creation_disposition,               // dwCreationDisposition //
                 flags,   // dwFlagsAndAttributes                  //
                 nullptr  // hTemplateFile                         //
      );

  if (handle == INVALID_HANDLE_VALUE) {
    FML_DLOG(ERROR) << "Could not open file. " << GetLastErrorMessage();
    return {};
  }

#ifdef WINUWP
  FILE_ID_INFO info;

  BOOL result = GetFileInformationByHandleEx(
      handle, FILE_INFO_BY_HANDLE_CLASS::FileIdInfo, &info,
      sizeof(FILE_ID_INFO));

  // Only cache if it is possible to get valid a fileinformation to extract the
  // fileid to ensure correct handle versioning.
  if (result) {
    fml::internal::os_win::DirCacheEntry fc{file_name, info.FileId};

    fml::internal::os_win::UniqueFDTraits::StoreCacheEntry(handle, fc);
  }
#endif

  return fml::UniqueFD{handle};
}

fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) {
  if (descriptor == INVALID_HANDLE_VALUE) {
    return fml::UniqueFD{};
  }

  HANDLE duplicated = INVALID_HANDLE_VALUE;

  if (!::DuplicateHandle(
          GetCurrentProcess(),  // source process
          descriptor,           // source handle
          GetCurrentProcess(),  // target process
          &duplicated,          // target handle
          0,      // desired access (ignored because DUPLICATE_SAME_ACCESS)
          FALSE,  // inheritable
          DUPLICATE_SAME_ACCESS)  // options
  ) {
    return fml::UniqueFD{};
  }

  return fml::UniqueFD{duplicated};
}

bool IsDirectory(const fml::UniqueFD& directory) {
  BY_HANDLE_FILE_INFORMATION info;
  if (!::GetFileInformationByHandle(directory.get(), &info)) {
    FML_DLOG(ERROR) << "Could not get file information. "
                    << GetLastErrorMessage();
    return false;
  }
  return info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
}

bool IsDirectory(const fml::UniqueFD& base_directory, const char* path) {
  return GetFileAttributesForUtf8Path(base_directory, path) &
         FILE_ATTRIBUTE_DIRECTORY;
}

bool IsFile(const std::string& path) {
  DWORD attributes = GetFileAttributesForUtf8Path(path.c_str());
  if (attributes == INVALID_FILE_ATTRIBUTES) {
    return false;
  }
  return !(attributes &
           (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT));
}

bool UnlinkDirectory(const char* path) {
  if (!::RemoveDirectory(StringToWideString(path).c_str())) {
    FML_DLOG(ERROR) << "Could not remove directory: '" << path << "'. "
                    << GetLastErrorMessage();
    return false;
  }
  return true;
}

bool UnlinkDirectory(const fml::UniqueFD& base_directory, const char* path) {
  if (!::RemoveDirectory(
          StringToWideString(GetAbsolutePath(base_directory, path)).c_str())) {
    FML_DLOG(ERROR) << "Could not remove directory: '" << path << "'. "
                    << GetLastErrorMessage();
    return false;
  }
  return true;
}

bool UnlinkFile(const char* path) {
  if (!::DeleteFile(StringToWideString(path).c_str())) {
    FML_DLOG(ERROR) << "Could not remove file: '" << path << "'. "
                    << GetLastErrorMessage();
    return false;
  }
  return true;
}

bool UnlinkFile(const fml::UniqueFD& base_directory, const char* path) {
  if (!::DeleteFile(
          StringToWideString(GetAbsolutePath(base_directory, path)).c_str())) {
    FML_DLOG(ERROR) << "Could not remove file: '" << path << "'. "
                    << GetLastErrorMessage();
    return false;
  }
  return true;
}

bool TruncateFile(const fml::UniqueFD& file, size_t size) {
  LARGE_INTEGER large_size;
  large_size.QuadPart = size;
  large_size.LowPart = SetFilePointer(file.get(), large_size.LowPart,
                                      &large_size.HighPart, FILE_BEGIN);
  if (large_size.LowPart == INVALID_SET_FILE_POINTER &&
      GetLastError() != NO_ERROR) {
    FML_DLOG(ERROR) << "Could not update file size. " << GetLastErrorMessage();
    return false;
  }

  if (!::SetEndOfFile(file.get())) {
    FML_DLOG(ERROR) << "Could not commit file size update. "
                    << GetLastErrorMessage();
    return false;
  }
  return true;
}

bool FileExists(const fml::UniqueFD& base_directory, const char* path) {
  return GetFileAttributesForUtf8Path(base_directory, path) !=
         INVALID_FILE_ATTRIBUTES;
}

bool WriteAtomically(const fml::UniqueFD& base_directory,
                     const char* file_name,
                     const Mapping& mapping) {
  if (file_name == nullptr) {
    return false;
  }

  auto file_path = GetAbsolutePath(base_directory, file_name);
  std::stringstream stream;
  stream << file_path << ".temp";
  auto temp_file_path = stream.str();

  auto temp_file =
      OpenFile(temp_file_path.c_str(), true, FilePermission::kReadWrite);

  if (!temp_file.is_valid()) {
    FML_DLOG(ERROR) << "Could not create temporary file.";
    return false;
  }

  if (!TruncateFile(temp_file, mapping.GetSize())) {
    FML_DLOG(ERROR) << "Could not truncate the file to the correct size. "
                    << GetLastErrorMessage();
    return false;
  }

  {
    FileMapping temp_file_mapping(temp_file, {FileMapping::Protection::kRead,
                                              FileMapping::Protection::kWrite});
    if (temp_file_mapping.GetSize() != mapping.GetSize()) {
      FML_DLOG(ERROR) << "Temporary file mapping size was incorrect. Is "
                      << temp_file_mapping.GetSize() << ". Should be "
                      << mapping.GetSize() << ".";
      return false;
    }

    if (temp_file_mapping.GetMutableMapping() == nullptr) {
      FML_DLOG(ERROR) << "Temporary file does not have a mutable mapping.";
      return false;
    }

    ::memcpy(temp_file_mapping.GetMutableMapping(), mapping.GetMapping(),
             mapping.GetSize());

    if (!::FlushViewOfFile(temp_file_mapping.GetMutableMapping(),
                           mapping.GetSize())) {
      FML_DLOG(ERROR) << "Could not flush file view. " << GetLastErrorMessage();
      return false;
    }

    if (!::FlushFileBuffers(temp_file.get())) {
      FML_DLOG(ERROR) << "Could not flush file buffers. "
                      << GetLastErrorMessage();
      return false;
    }

    // File mapping is detroyed.
  }

  temp_file.reset();

  if (!::MoveFile(StringToWideString(temp_file_path).c_str(),
                  StringToWideString(file_path).c_str())) {
    FML_DLOG(ERROR)
        << "Could not replace temp file at correct path. File path: "
        << file_path << ". Temp file path: " << temp_file_path << " "
        << GetLastErrorMessage();
    return false;
  }

  return true;
}

bool VisitFiles(const fml::UniqueFD& directory, const FileVisitor& visitor) {
  std::string search_pattern = GetFullHandlePath(directory) + "\\*";
  WIN32_FIND_DATA find_file_data;
  HANDLE find_handle = ::FindFirstFile(
      StringToWideString(search_pattern).c_str(), &find_file_data);

  if (find_handle == INVALID_HANDLE_VALUE) {
    FML_DLOG(ERROR) << "Can't open the directory. Error: "
                    << GetLastErrorMessage();
    return true;  // continue to visit other files
  }

  do {
    std::string filename = WideStringToString(find_file_data.cFileName);
    if (filename != "." && filename != "..") {
      if (!visitor(directory, filename)) {
        ::FindClose(find_handle);
        return false;
      }
    }
  } while (::FindNextFile(find_handle, &find_file_data));
  ::FindClose(find_handle);
  return true;
}

}  // namespace fml
