# typed: strict
class Job::FaPostFurArchiverPostFileJob < Scraper::JobBase
  extend T::Sig
  include Domain::StaticFileJobHelper

  queue_as :static_file
  discard_on Scraper::JobBase::JobError, ActiveJob::DeserializationError

  sig { override.returns(Symbol) }
  def self.http_factory_method
    :get_fur_archiver_http_client
  end

  sig { override.params(args: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
  def perform(args)
    post_file = T.cast(args[:post_file], Domain::PostFile)
    logger.tagged(make_arg_tag(post_file), make_arg_tag(post_file.post)) do
      handle(post_file)
    end
  end

  FA_URL_PATTERN =
    %r{
    https://(d\.facdn\.net|d\.furaffinity\.net)/art/([^\/]+)/(\d+)/([^\/]+)
  }x

  sig { params(post_file: Domain::PostFile).void }
  def handle(post_file)
    post = T.cast(post_file.post, Domain::Post::FaPost)

    if post.file != post_file && post.file&.state_ok?
      logger.info("file already downloaded, deleting old file")
      post_file.destroy
      return
    end

    if post_file.state_ok? && post_file.last_status_code == 200
      logger.info("file already downloaded, skipping")
      return
    end

    if post.tried_from_fur_archiver?
      logger.warn("already tried to download from fur archiver, skipping")
      return
    end

    unless post_file.last_status_code == 404
      logger.warn("last status code is not 404, skipping")
      return
    end

    unless post_file.state_terminal_error?
      logger.warn("post file not in terminal error state, skipping")
      return
    end

    user_url_name = post.creator&.url_name
    fatal_error("no user url name") unless user_url_name

    fa_file_url_str = post_file.url_str
    fatal_error("no fa file url") unless fa_file_url_str

    match = fa_file_url_str.match(FA_URL_PATTERN)
    unless match
      if fa_file_url_str.include?("#{user_url_name}/stories/")
        logger.warn("old stories URL, force rescan")
        post.reload
        Domain::Fa::Job::ScanPostJob.perform_now(
          { post: post, force_scan: true },
        )
        post.reload
        unless post.state_ok?
          fatal_error("post not in ok state after rescan: #{post.state}")
        end
        return if post.file&.state_ok? || post.file&.state_pending?
        match = fa_file_url_str.match(FA_URL_PATTERN)
        unless match
          fatal_error("invalid fa file url after rescan: #{fa_file_url_str}")
        end
      else
        fatal_error("invalid fa file url: #{fa_file_url_str}")
      end
    end

    unless url_user_url_name = match.captures[1]
      fatal_error("no user url name in url: #{fa_file_url_str}")
    end

    unless url_file_name = match.captures[3]
      fatal_error("no file name in url: #{fa_file_url_str}")
    end

    unless user_url_name == url_user_url_name
      logger.tagged(
        make_tag("in_db", user_url_name),
        make_tag("in_url", url_user_url_name),
      ) { fatal_error("user name mismatch") }
    end

    fur_archiver_url_str =
      "https://furarchiver.net/File/View?artist=#{url_user_url_name}&filename=#{url_file_name}"

    post.tried_from_fur_archiver = true
    post_file = post.files.build(url_str: fur_archiver_url_str)

    begin
      response = http_client.get(fur_archiver_url_str)
    rescue Scraper::HttpClient::InvalidURLError,
           Curl::Err::HostResolutionError => e
      post_file.state_terminal_error!
      post_file.error_message = e.message
      logger.error(
        format_tags(
          "invalid fur archiver url, terminal error state",
          make_tag("error_message", e.message),
          make_tag("url", fur_archiver_url_str),
        ),
      )
      return
    ensure
      post.save! if post
    end

    post_file.save!
    post.reload

    handle_file_download_response(post_file, response)
  end
end
