//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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)
//
#include "td/telegram/StickerPhotoSize.h"

#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"

#include "td/utils/logging.h"

namespace td {

Result<unique_ptr<StickerPhotoSize>> StickerPhotoSize::get_sticker_photo_size(
    Td *td, const td_api::object_ptr<td_api::chatPhotoSticker> &sticker) {
  if (sticker == nullptr) {
    return Status::Error(400, "Sticker must not be null");
  }
  if (sticker->type_ == nullptr) {
    return Status::Error(400, "Type must be non-null");
  }
  if (sticker->background_fill_ == nullptr) {
    return Status::Error(400, "Background must be non-null");
  }
  auto result = make_unique<StickerPhotoSize>();
  switch (sticker->type_->get_id()) {
    case td_api::chatPhotoStickerTypeRegularOrMask::ID: {
      auto type = static_cast<const td_api::chatPhotoStickerTypeRegularOrMask *>(sticker->type_.get());
      result->type_ = Type::Sticker;
      result->sticker_set_id_ = StickerSetId(type->sticker_set_id_);
      result->sticker_id_ = type->sticker_id_;
      if (!td->stickers_manager_->have_sticker(result->sticker_set_id_, result->sticker_id_)) {
        return Status::Error(400, "Sticker not found");
      }
      break;
    }
    case td_api::chatPhotoStickerTypeCustomEmoji::ID: {
      auto type = static_cast<const td_api::chatPhotoStickerTypeCustomEmoji *>(sticker->type_.get());
      result->type_ = Type::CustomEmoji;
      result->custom_emoji_id_ = CustomEmojiId(type->custom_emoji_id_);
      if (!td->stickers_manager_->have_custom_emoji(result->custom_emoji_id_)) {
        return Status::Error(400, "Custom emoji not found");
      }
      break;
    }
  }
  auto fill = sticker->background_fill_.get();
  switch (fill->get_id()) {
    case td_api::backgroundFillSolid::ID: {
      auto solid = static_cast<const td_api::backgroundFillSolid *>(fill);
      result->background_colors_.push_back(solid->color_);
      break;
    }
    case td_api::backgroundFillGradient::ID: {
      auto gradient = static_cast<const td_api::backgroundFillGradient *>(fill);
      result->background_colors_.push_back(gradient->top_color_);
      result->background_colors_.push_back(gradient->bottom_color_);
      break;
    }
    case td_api::backgroundFillFreeformGradient::ID: {
      auto freeform = static_cast<const td_api::backgroundFillFreeformGradient *>(fill);
      if (freeform->colors_.size() != 3 && freeform->colors_.size() != 4) {
        return Status::Error(400, "Invalid number of colors specified");
      }
      result->background_colors_ = freeform->colors_;
      break;
    }
    default:
      UNREACHABLE();
      break;
  }
  for (auto &color : result->background_colors_) {
    color &= 0xFFFFFF;
  }
  return std::move(result);
}

telegram_api::object_ptr<telegram_api::VideoSize> StickerPhotoSize::get_input_video_size_object(Td *td) const {
  switch (type_) {
    case Type::Sticker:
      return telegram_api::make_object<telegram_api::videoSizeStickerMarkup>(
          td->stickers_manager_->get_input_sticker_set(sticker_set_id_), sticker_id_,
          vector<int32>(background_colors_));
    case Type::CustomEmoji:
      return telegram_api::make_object<telegram_api::videoSizeEmojiMarkup>(custom_emoji_id_.get(),
                                                                           vector<int32>(background_colors_));
    default:
      UNREACHABLE();
      return nullptr;
  }
}

unique_ptr<StickerPhotoSize> StickerPhotoSize::get_sticker_photo_size(
    Td *td, telegram_api::object_ptr<telegram_api::VideoSize> &&size_ptr) {
  CHECK(size_ptr != nullptr);
  auto result = make_unique<StickerPhotoSize>();
  bool is_valid = false;
  switch (size_ptr->get_id()) {
    case telegram_api::videoSizeEmojiMarkup::ID: {
      auto size = move_tl_object_as<telegram_api::videoSizeEmojiMarkup>(size_ptr);
      result->type_ = Type::CustomEmoji;
      result->custom_emoji_id_ = CustomEmojiId(size->emoji_id_);
      result->background_colors_ = std::move(size->background_colors_);
      is_valid = result->custom_emoji_id_.is_valid();
      break;
    }
    case telegram_api::videoSizeStickerMarkup::ID: {
      auto size = move_tl_object_as<telegram_api::videoSizeStickerMarkup>(size_ptr);
      result->type_ = Type::Sticker;
      result->sticker_set_id_ = td->stickers_manager_->add_sticker_set(std::move(size->stickerset_));
      result->sticker_id_ = size->sticker_id_;
      result->background_colors_ = std::move(size->background_colors_);
      is_valid = result->sticker_set_id_.is_valid() && result->sticker_id_ != 0;
      break;
    }
    default:
      UNREACHABLE();
  }
  if (!is_valid || result->background_colors_.empty() || result->background_colors_.size() > 4) {
    LOG(ERROR) << "Receive invalid " << *result;
    return {};
  }
  for (auto &color : result->background_colors_) {
    color &= 0xFFFFFF;
  }
  return result;
}

td_api::object_ptr<td_api::chatPhotoSticker> StickerPhotoSize::get_chat_photo_sticker_object() const {
  td_api::object_ptr<td_api::ChatPhotoStickerType> sticker_type;
  switch (type_) {
    case Type::Sticker:
      sticker_type = td_api::make_object<td_api::chatPhotoStickerTypeRegularOrMask>(sticker_set_id_.get(), sticker_id_);
      break;
    case Type::CustomEmoji:
      sticker_type = td_api::make_object<td_api::chatPhotoStickerTypeCustomEmoji>(custom_emoji_id_.get());
      break;
    default:
      UNREACHABLE();
      return nullptr;
  }
  CHECK(sticker_type != nullptr);

  auto background_fill = [&](vector<int32> colors) -> td_api::object_ptr<td_api::BackgroundFill> {
    switch (colors.size()) {
      case 1:
        return td_api::make_object<td_api::backgroundFillSolid>(colors[0]);
      case 2:
        return td_api::make_object<td_api::backgroundFillGradient>(colors[0], colors[1], 0);
      case 3:
      case 4:
        return td_api::make_object<td_api::backgroundFillFreeformGradient>(std::move(colors));
      default:
        UNREACHABLE();
        return nullptr;
    }
  }(background_colors_);

  return td_api::make_object<td_api::chatPhotoSticker>(std::move(sticker_type), std::move(background_fill));
}

bool operator==(const StickerPhotoSize &lhs, const StickerPhotoSize &rhs) {
  return lhs.type_ == rhs.type_ && lhs.sticker_set_id_ == rhs.sticker_set_id_ && lhs.sticker_id_ == rhs.sticker_id_ &&
         lhs.custom_emoji_id_ == rhs.custom_emoji_id_ && lhs.background_colors_ == rhs.background_colors_;
}

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

StringBuilder &operator<<(StringBuilder &string_builder, const StickerPhotoSize &sticker_photo_size) {
  switch (sticker_photo_size.type_) {
    case StickerPhotoSize::Type::Sticker:
      return string_builder << sticker_photo_size.sticker_id_ << " from " << sticker_photo_size.sticker_set_id_
                            << " on " << sticker_photo_size.background_colors_;
    case StickerPhotoSize::Type::CustomEmoji:
      return string_builder << sticker_photo_size.custom_emoji_id_ << " on " << sticker_photo_size.background_colors_;
    default:
      UNREACHABLE();
      return string_builder;
  }
}

}  // namespace td