// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/segmentation_platform/embedder/tab_fetcher.h"

#include "base/memory/raw_ptr.h"
#include "base/notimplemented.h"
#include "base/time/time.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h"
#include "components/sync_sessions/synced_session.h"

namespace segmentation_platform {
namespace {

void FillTabsFromSessionsAfterTime(
    const std::vector<raw_ptr<const sync_sessions::SyncedSession,
                              VectorExperimental>> sessions,
    std::vector<TabFetcher::TabEntry>& tabs,
    base::Time tabs_loaded_after_timestamp) {
  for (const sync_sessions::SyncedSession* session : sessions) {
    for (const auto& session_and_window : session->windows) {
      const auto& window = session_and_window.second->wrapped_window;
      for (const auto& tab : window.tabs) {
        if (tab->timestamp >= tabs_loaded_after_timestamp) {
          tabs.emplace_back(tab->tab_id, session->GetSessionTag());
        }
      }
    }
  }
}

}  // namespace

TabFetcher::TabEntry::TabEntry(SessionID tab_id, const std::string& session_tag)
    : session_tag(session_tag), tab_id(tab_id), web_contents_data(nullptr) {}

TabFetcher::TabEntry::TabEntry(SessionID tab_id,
                               content::WebContents* webcontents,
                               TabAndroid* tab_android)
    : tab_id(tab_id),
      web_contents_data(webcontents),
      tab_android_data(tab_android) {}

TabFetcher::TabFetcher(sync_sessions::SessionSyncService* session_sync_service)
    : session_sync_service_(session_sync_service) {}

bool TabFetcher::FillAllRemoteTabs(std::vector<TabEntry>& tabs) {
  auto* open_ui_delegate = session_sync_service_->GetOpenTabsUIDelegate();
  if (!open_ui_delegate) {
    return false;
  }
  std::vector<raw_ptr<const sync_sessions::SyncedSession, VectorExperimental>>
      sessions;
  open_ui_delegate->GetAllForeignSessions(&sessions);
  FillTabsFromSessionsAfterTime(sessions, tabs, base::Time());
  return true;
}

bool TabFetcher::FillAllRemoteTabsAfterTime(
    std::vector<TabEntry>& tabs,
    base::Time tabs_loaded_after_timestamp) {
  auto* open_ui_delegate = session_sync_service_->GetOpenTabsUIDelegate();
  if (!open_ui_delegate) {
    return false;
  }
  std::vector<raw_ptr<const sync_sessions::SyncedSession, VectorExperimental>>
      sessions;
  open_ui_delegate->GetAllForeignSessions(&sessions);
  FillTabsFromSessionsAfterTime(sessions, tabs, tabs_loaded_after_timestamp);
  return true;
}

bool TabFetcher::FillAllLocalTabs(std::vector<TabEntry>& tabs) {
  if (FillAllLocalTabsFromTabModel(tabs)) {
    return true;
  }
  return FillAllLocalTabsFromSyncSessions(tabs);
}

TabFetcher::Tab TabFetcher::FindTab(const TabEntry& entry) {
  auto* open_ui_delegate = session_sync_service_->GetOpenTabsUIDelegate();
  if (!open_ui_delegate || entry.session_tag.empty()) {
    return FindLocalTab(entry);
  }
  const sessions::SessionTab* tab;
  open_ui_delegate->GetForeignTab(entry.session_tag, entry.tab_id, &tab);
  GURL url =
      tab->navigations.size() ? tab->navigations.back().virtual_url() : GURL();
  return Tab{.session_tab = tab,
             .tab_url = url,
             .time_since_modified = base::Time::Now() - tab->timestamp};
}

bool TabFetcher::FillAllLocalTabsFromTabModel(std::vector<TabEntry>& tabs) {
  NOTIMPLEMENTED();
  return false;
}

bool TabFetcher::FillAllLocalTabsFromSyncSessions(std::vector<TabEntry>& tabs) {
  const sync_sessions::SyncedSession* local_session = nullptr;
  auto* open_ui_delegate = session_sync_service_->GetOpenTabsUIDelegate();
  open_ui_delegate->GetLocalSession(&local_session);
  if (!local_session) {
    return false;
  }
  FillTabsFromSessionsAfterTime({local_session}, tabs, base::Time());
  return true;
}

TabFetcher::Tab TabFetcher::FindLocalTab(const TabEntry& entry) {
  NOTIMPLEMENTED();
  return Tab{};
}

size_t TabFetcher::GetRemoteTabsCountAfterTime(
    base::Time tabs_loaded_after_timestamp) {
  std::vector<TabFetcher::TabEntry> all_tabs;
  FillAllRemoteTabsAfterTime(all_tabs, tabs_loaded_after_timestamp);
  return all_tabs.size();
}

std::optional<base::Time> TabFetcher::GetLatestRemoteSessionModifiedTime() {
  auto* open_ui_delegate = session_sync_service_->GetOpenTabsUIDelegate();
  if (!open_ui_delegate) {
    return std::nullopt;
  }
  std::vector<raw_ptr<const sync_sessions::SyncedSession, VectorExperimental>>
      sessions;
  open_ui_delegate->GetAllForeignSessions(&sessions);
  if (sessions.empty()) {
    return std::nullopt;
  }
  // Get latest session modified time.
  return sessions[0]->GetModifiedTime();
}

}  // namespace segmentation_platform
