# typed: strict
class Domain::E621::TagUtil
  extend T::Sig
  include HasColorLogger

  TagAndCategory = Struct.new(:name, :category)

  sig do
    params(
      post_json: T::Hash[String, T.untyped],
      caused_by_entry: T.nilable(HttpLogEntry),
      force_update: T::Boolean,
    ).returns(Domain::Post::E621Post)
  end
  def self.initialize_or_update_post(
    post_json:,
    caused_by_entry: nil,
    force_update: false
  )
    # create all posts that don't already exist
    e621_id = T.cast(post_json["id"], Integer)
    e621_post = Domain::Post::E621Post.find_or_initialize_by(e621_id: e621_id)

    e621_updated_at = Time.zone.parse(post_json["updated_at"])
    if !force_update && (e621_post.e621_updated_at == e621_updated_at)
      logger.info(
        "post #{e621_post.id} / #{e621_post.e621_id} updated at #{e621_updated_at.to_s.bold} is unchanged",
      )
      return e621_post
    end

    e621_post.e621_updated_at = e621_updated_at
    e621_post.caused_by_entry_id = caused_by_entry.id if caused_by_entry

    e621_md5 = T.cast(post_json["file"]["md5"], String)

    force_new_file = false
    if e621_post.md5 && e621_post.md5 != e621_md5
      logger.warn(
        "md5 changed for post: #{e621_post.md5.to_s.bold} => #{e621_md5.to_s.bold}",
      )
      e621_post.prev_md5s ||= []
      e621_post.prev_md5s << e621_post.md5
      force_new_file = true
    end

    file =
      if !force_new_file && (file = e621_post.file)
        file
      else
        e621_post.files.build do |new_file|
          logger.info(
            "building file for post #{e621_post.id} / #{e621_post.e621_id}",
          )
          new_file.enqueue_job_after_save(
            Domain::E621::Job::StaticFileJob,
            { post_file: new_file, caused_by_entry: },
          )
        end
      end

    file.url_str =
      begin
        file_json = post_json["file"]
        file_json["url"] || md5_to_file_url(e621_md5, file_json["ext"])
      end
    e621_post.md5 = e621_md5
    e621_post.posted_at = post_json["created_at"]
    e621_post.description = post_json["description"]
    e621_post.rating = post_json["rating"]
    e621_post.score = post_json["score"]["total"]
    e621_post.score_up = post_json["score"]["up"]
    e621_post.score_down = post_json["score"]["down"]
    e621_post.num_favorites = post_json["fav_count"]
    e621_post.num_comments = post_json["comment_count"]
    e621_post.change_seq = post_json["change_seq"]
    e621_post.parent_post_e621_id = post_json["relationships"]["parent_id"]

    e621_post.flags_array =
      post_json["flags"].to_a.select(&:second).map(&:first)
    e621_post.pools_array = post_json["pools"]
    e621_post.sources_array = post_json["sources"]
    e621_post.tags_array = post_json["tags"]

    begin
      file.save!
    rescue StandardError
      puts "error saving file"
    end
    e621_post
  end

  sig { params(md5: String, ext: String).returns(String) }
  def self.md5_to_file_url(md5, ext)
    "https://static1.e621.net/data/#{md5[0...2]}/#{md5[2...4]}/#{md5}.#{ext}"
  end
end
