#pragma once

#include "render/animation/animation_manager.h"
#include "shell/control_center/control_center_services.h"
#include "shell/control_center/tab.h"
#include "shell/control_center/tabs/audio_tab.h"
#include "shell/control_center/tabs/bluetooth_tab.h"
#include "shell/control_center/tabs/calendar_tab.h"
#include "shell/control_center/tabs/home_tab.h"
#include "shell/control_center/tabs/media_tab.h"
#include "shell/control_center/tabs/monitor_tab.h"
#include "shell/control_center/tabs/network_tab.h"
#include "shell/control_center/tabs/notifications_tab.h"
#include "shell/control_center/tabs/power_tab.h"
#include "shell/control_center/tabs/system_tab.h"
#include "shell/control_center/tabs/weather_tab.h"
#include "shell/panel/panel.h"
#include "ui/controls/scroll_view.h"

#include <array>
#include <chrono>
#include <cstdint>
#include <memory>
#include <string_view>
#include <vector>

class BluetoothAgent;
class BluetoothService;
class BrightnessService;
class Button;
class CompositorPlatform;
class ConfigService;
class DependencyService;
class EasyEffectsService;
class Flex;
class HttpClient;
class IdleInhibitor;
class IpcService;
class InputArea;
class Label;
class MprisService;
class Node;
class RovingListNavHost;
class NetworkSecretAgent;
class INetworkService;
class GammaService;
class NotificationManager;
class PipeWireService;
class PipeWireSpectrum;
class PowerProfilesService;
class ScreenTimeService;
class SystemMonitorService;
class CalendarService;
class UPowerService;
class Wallpaper;
class WeatherService;
class ClipboardService;

namespace noctalia::theme {
  class ThemeService;
}
namespace scripting {
  class ScriptApiContext;
}

class AccountsService;
class ThumbnailService;

class ControlCenterPanel : public Panel {
public:
  explicit ControlCenterPanel(const ControlCenterServices& services);

  // Tabs the user may hide from the Settings GUI (every tab except Home).
  // Keys match the [control_center] hidden_tabs entries.
  struct TabCatalogEntry {
    std::string_view key;
    std::string_view titleKey;
  };
  [[nodiscard]] static std::vector<TabCatalogEntry> hideableTabCatalog();

  void create() override;
  void onFrameTick(float deltaMs) override;
  void onOpen(std::string_view context) override;
  void onClose() override;
  [[nodiscard]] bool dismissTransientUi() override;
  [[nodiscard]] bool isContextActive(std::string_view context) const override;
  [[nodiscard]] bool handleGlobalKey(std::uint32_t sym, std::uint32_t modifiers, bool pressed, bool preedit) override;
  [[nodiscard]] bool deferExternalRefresh() const override;
  [[nodiscard]] bool deferPointerRelayout() const override;
  [[nodiscard]] float preferredWidth() const override;
  [[nodiscard]] float preferredHeight() const override { return scaled(520.0F); }
  [[nodiscard]] PanelPlacement panelPlacement() const noexcept override;
  [[nodiscard]] bool showsSidebar() const noexcept { return m_showSidebar; }

private:
  void onPanelCardOpacityChanged(float opacity) override;
  void doLayout(Renderer& renderer, float width, float height) override;
  void doUpdate(Renderer& renderer) override;

  enum class TabId : std::uint8_t {
    Home,
    Media,
    Audio,
    Monitor,
    System,
    Network,
    Bluetooth,
    Weather,
    Calendar,
    Notifications,
    ScreenTime,
    Power,
    Count,
  };

  struct TabMeta {
    TabId id;
    const char* key;
    const char* titleKey;
    const char* glyph;
  };

  static constexpr std::size_t kTabCount = static_cast<std::size_t>(TabId::Count);
  static constexpr std::array<TabMeta, kTabCount> kTabs{{
      {TabId::Home, "home", "control-center.tabs.home", "home"},
      {TabId::Media, "media", "control-center.tabs.media", "disc-filled"},
      {TabId::Audio, "audio", "control-center.tabs.audio", "volume"},
      {TabId::Monitor, "monitor", "control-center.tabs.monitor", "device-desktop"},
      {TabId::System, "system", "control-center.tabs.system", "activity-heartbeat"},
      {TabId::Power, "power", "control-center.tabs.power", "battery-charging-2"},
      {TabId::Network, "network", "control-center.tabs.network", "wifi"},
      {TabId::Bluetooth, "bluetooth", "control-center.tabs.bluetooth", "bluetooth"},
      {TabId::Weather, "weather", "control-center.tabs.weather", "weather-cloud-sun"},
      {TabId::Calendar, "calendar", "control-center.tabs.calendar", "calendar-event"},
      {TabId::Notifications, "notifications", "control-center.tabs.notifications", "bell"},
      {TabId::ScreenTime, "screen-time", "control-center.tabs.screen-time", "hourglass"},
  }};

  void selectTab(TabId tab, bool animated = false);
  void selectAdjacentVisibleTab(int direction);
  void wireSidebarScroll(InputArea* area);
  void scrollFocusedInputIntoView(InputArea* area) override;
  void scrollSidebarNodeIntoView(const Node* node);
  void scheduleMprisRefreshFor(TabId tab);
  void updateTabChrome(TabId tab);
  void applyTabContainerVisibility(TabId activeTab);
  void layoutTabContainers(float bodyWidth, float bodyHeight);
  void layoutFullSidebarWidth(Renderer& renderer);
  void resetTabContainerTransforms();
  void startTabTransition(TabId from, TabId to);
  void finishTabTransition();
  void applyTabTransitionLayout();
  [[nodiscard]] int visibleTabOrdinal(TabId tab) const;
  void syncTabVisibility();
  [[nodiscard]] bool isTabFeatureAvailable(TabId tab) const;
  [[nodiscard]] bool isTabVisible(TabId tab) const;
  [[nodiscard]] bool isTabShown(TabId tab) const;
  [[nodiscard]] static std::string_view tabKey(TabId tab);
  [[nodiscard]] TabId firstVisibleTab() const;
  [[nodiscard]] TabId tabFromContext(std::string_view context) const;
  [[nodiscard]] bool isDirectSectionOpenContext(std::string_view context) const;
  [[nodiscard]] ControlCenterSidebarMode sidebarModeForOpen(std::string_view context) const;
  [[nodiscard]] static std::size_t tabIndex(TabId id);

  // Tab instances (long-lived, survive panel open/close cycles)
  std::array<std::unique_ptr<Tab>, kTabCount> m_tabs;

  // Panel UI structure (rebuilt each create(), nulled in onClose())
  Flex* m_rootLayout = nullptr;
  Flex* m_sidebar = nullptr;
  ScrollView* m_sidebarScrollView = nullptr;
  ScrollViewState m_sidebarScrollState{};
  RovingListNavHost* m_sidebarNav = nullptr;
  InputArea* m_sidebarScrollArea = nullptr;
  Flex* m_content = nullptr;
  InputArea* m_contentDismissArea = nullptr;
  Flex* m_contentHeader = nullptr;
  Flex* m_contentHeaderActions = nullptr;
  Label* m_contentTitle = nullptr;
  Button* m_closeButton = nullptr;
  Flex* m_tabBodies = nullptr;
  std::array<Button*, kTabCount> m_tabButtons{};
  std::array<Flex*, kTabCount> m_tabContainers{};
  std::array<Flex*, kTabCount> m_tabHeaderActions{};
  TabId m_activeTab = TabId::Home;
  bool m_activeTabForced = false;
  ConfigService* m_config = nullptr;
  MprisService* m_mpris = nullptr;
  NotificationManager* m_notificationManager = nullptr;
  DependencyService* m_dependencies = nullptr;
  bool m_compact = false;
  bool m_showSidebar = true;
  bool m_hasPowerServices = false;
  bool m_mprisRefreshScheduled = false;
  std::chrono::steady_clock::time_point m_lastMprisRefreshAt;
  AnimationManager::Id m_tabTransitionAnimId = 0;
  TabId m_tabTransitionOutgoing = TabId::Home;
  float m_tabTransitionProgress = 1.0F;
  int m_tabTransitionDirection = 1;
  bool m_tabTransitionActive = false;
  bool m_firstOpenAfterCreate = false;
};
