//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once

#include "td/telegram/CustomEmojiId.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogParticipant.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/Photo.h"
#include "td/telegram/RichMessageMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"

#include "td/utils/common.h"
#include "td/utils/FlatHashMap.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"

#include <functional>

namespace td {

class Dependencies;
struct GetWebPageBlockObjectContext;
class RichText;
class Td;

struct GetInputPageBlockContext {
  const Td *td_ = nullptr;
  vector<telegram_api::object_ptr<telegram_api::InputPhoto>> photos_;
  vector<telegram_api::object_ptr<telegram_api::InputDocument>> documents_;
  const vector<RichMessageMedia> *media_ = nullptr;
  size_t media_pos_ = 0;
};

class WebPageBlock {
 protected:
  enum class Type : int32 {
    Title,
    Subtitle,
    AuthorDate,
    Header,
    Subheader,
    Paragraph,
    Preformatted,
    Footer,
    Divider,
    Anchor,
    List,
    BlockQuote,
    PullQuote,
    Animation,
    Photo,
    Video,
    Cover,
    Embedded,
    EmbeddedPost,
    Collage,
    Slideshow,
    ChatLink,
    Audio,
    Kicker,
    Table,
    Details,
    RelatedArticles,
    Map,
    VoiceNote,
    Heading,
    Math,
    Thinking,
    BlockQuoteBlocks,
    Size
  };

  virtual Type get_type() const = 0;

  template <class F>
  static void call_impl(Type type, const WebPageBlock *ptr, F &&f);

  template <class StorerT>
  void store(StorerT &storer) const;

  template <class ParserT>
  static unique_ptr<WebPageBlock> parse(ParserT &parser);

  template <class StorerT>
  friend void store_web_page_block(const unique_ptr<WebPageBlock> &block, StorerT &storer);

  template <class ParserT>
  friend void parse_web_page_block(unique_ptr<WebPageBlock> &block, ParserT &parser);

  friend bool operator==(const WebPageBlock &lhs, const WebPageBlock &rhs);

  using Context = GetWebPageBlockObjectContext;

  using InputContext = GetInputPageBlockContext;

 public:
  WebPageBlock() = default;
  WebPageBlock(const WebPageBlock &) = delete;
  WebPageBlock &operator=(const WebPageBlock &) = delete;
  WebPageBlock(WebPageBlock &&) = delete;
  WebPageBlock &operator=(WebPageBlock &&) = delete;
  virtual ~WebPageBlock() = default;

  virtual void append_file_ids(const Td *td, vector<FileId> &file_ids) const = 0;

  virtual void append_rich_message_media(vector<RichMessageMedia> &media) const {
  }

  virtual void add_dependencies(Dependencies &dependencies) const = 0;

  virtual void for_each_rich_text(bool recurse_text,
                                  const std::function<void(const RichText *text)> &callback) const = 0;

  void for_each_text(const std::function<void(Slice text)> &callback) const;

  void append_user_ids(vector<UserId> &user_ids) const;

  bool has_bot_commands() const;

  vector<string> get_hashtags() const;

  vector<CustomEmojiId> get_custom_emoji_ids() const;

  virtual bool can_send(const RestrictedRights &rights) const {
    return true;
  }

  virtual int32 get_index_mask() const = 0;

  virtual unique_ptr<WebPageBlock> clone() const = 0;

  virtual telegram_api::object_ptr<telegram_api::PageBlock> get_input_page_block(InputContext &context) const = 0;

  virtual td_api::object_ptr<td_api::PageBlock> get_page_block_object(Context *context) const = 0;

  static bool are_allowed_album_block_types(const vector<unique_ptr<WebPageBlock>> &page_blocks);
};

void store(const unique_ptr<WebPageBlock> &block, LogEventStorerCalcLength &storer);

void store(const unique_ptr<WebPageBlock> &block, LogEventStorerUnsafe &storer);

void parse(unique_ptr<WebPageBlock> &block, LogEventParser &parser);

bool operator==(const WebPageBlock &lhs, const WebPageBlock &rhs);

inline bool operator!=(const WebPageBlock &lhs, const WebPageBlock &rhs) {
  return !(lhs == rhs);
}

vector<unique_ptr<WebPageBlock>> get_web_page_blocks(
    Td *td, vector<tl_object_ptr<telegram_api::PageBlock>> page_block_ptrs,
    const FlatHashMap<int64, FileId> &animations, const FlatHashMap<int64, FileId> &audios,
    const FlatHashMap<int64, FileId> &documents, const FlatHashMap<int64, unique_ptr<Photo>> &photos,
    const FlatHashMap<int64, FileId> &videos, const FlatHashMap<int64, FileId> &voice_notes);

Result<vector<unique_ptr<WebPageBlock>>> get_web_page_blocks(
    Td *td, DialogId dialog_id, vector<td_api::object_ptr<td_api::InputPageBlock>> input_page_blocks);

int32 get_web_page_blocks_index_mask(const vector<unique_ptr<WebPageBlock>> &page_blocks);

vector<unique_ptr<WebPageBlock>> clone_web_page_blocks(const vector<unique_ptr<WebPageBlock>> &page_blocks);

vector<telegram_api::object_ptr<telegram_api::PageBlock>> get_input_page_blocks(
    const vector<unique_ptr<WebPageBlock>> &page_blocks, GetInputPageBlockContext &context);

vector<RichMessageMedia> get_page_blocks_rich_message_media(const vector<unique_ptr<WebPageBlock>> &page_blocks);

vector<td_api::object_ptr<td_api::PageBlock>> get_page_blocks_object(
    const vector<unique_ptr<WebPageBlock>> &page_blocks, Td *td, Slice base_url, Slice real_url,
    bool skip_bot_commands);

}  // namespace td
