// 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.

#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_LIFECYCLE_MANAGER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_LIFECYCLE_MANAGER_H_

#include <Windows.h>

#include <cstdint>
#include <map>
#include <mutex>
#include <optional>
#include <set>

#include "flutter/shell/platform/common/app_lifecycle_state.h"

namespace flutter {

class FlutterWindowsEngine;

/// An event representing a change in window state that may update the
// application lifecycle state.
enum class WindowStateEvent {
  kShow,
  kHide,
  kFocus,
  kUnfocus,
};

/// A manager for lifecycle events of the top-level windows.
///
/// WndProc is called for window messages of the top-level Flutter window.
/// ExternalWindowMessage is called for non-flutter top-level window messages.
/// OnWindowStateEvent is called when the visibility or focus state of a window
///   is changed, including the FlutterView window.
class WindowsLifecycleManager {
 public:
  WindowsLifecycleManager(FlutterWindowsEngine* engine);
  virtual ~WindowsLifecycleManager();

  // Called when the engine is notified it should quit, e.g. by an application
  // call to `exitApplication`. When window is std::nullopt, this quits the
  // application. Otherwise, it holds the HWND of the window that initiated the
  // request, and exit_code is unused.
  virtual void Quit(std::optional<HWND> window,
                    std::optional<WPARAM> wparam,
                    std::optional<LPARAM> lparam,
                    UINT exit_code);

  // Intercept top level window WM_CLOSE message and listen to events that may
  // update the application lifecycle.
  bool WindowProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l, LRESULT* result);

  // Signal to start consuming WM_CLOSE messages.
  void BeginProcessingClose();

  // Update the app lifecycle state in response to a change in window state.
  // When the app lifecycle state actually changes, this sends a platform
  // message to the framework notifying it of the state change.
  virtual void SetLifecycleState(AppLifecycleState state);

  // Respond to a change in window state. Transitions as follows:
  // When the only visible window is hidden, transition from resumed or
  // inactive to hidden.
  // When the only focused window is unfocused, transition from resumed to
  // inactive.
  // When a window is focused, transition from inactive to resumed.
  // When a window is shown, transition from hidden to inactive.
  virtual void OnWindowStateEvent(HWND hwnd, WindowStateEvent event);

  AppLifecycleState GetLifecycleState() { return state_; }

  // Called by the engine when a non-Flutter window receives an event that may
  // alter the lifecycle state. The logic for external windows must differ from
  // that used for FlutterWindow instances, because:
  // - FlutterWindow does not receive WM_SHOW messages,
  // - When FlutterWindow receives WM_SIZE messages, wparam stores no meaningful
  //   information, whereas it usually indicates the action which changed the
  //   window size.
  // When this returns a result, the message has been consumed and should not be
  // processed further. Currently, it will always return nullopt.
  std::optional<LRESULT> ExternalWindowMessage(HWND hwnd,
                                               UINT message,
                                               WPARAM wparam,
                                               LPARAM lparam);

 protected:
  // Check the number of top-level windows associated with this process, and
  // return true only if there are 1 or fewer.
  virtual bool IsLastWindowOfProcess();

  virtual void DispatchMessage(HWND window,
                               UINT msg,
                               WPARAM wparam,
                               LPARAM lparam);

 private:
  FlutterWindowsEngine* engine_;

  std::map<std::tuple<HWND, WPARAM, LPARAM>, int> sent_close_messages_;

  bool process_close_;

  std::set<HWND> visible_windows_;

  std::set<HWND> focused_windows_;

  std::mutex state_update_lock_;

  flutter::AppLifecycleState state_;
};

}  // namespace flutter

#endif  // FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_LIFECYCLE_MANAGER_H_
