# frozen_string_literal: true

#
# Copyright 2013 whiteleaf. All rights reserved.
#

require "open-uri"
require "zlib"
require "yaml"
require "json"
require "memoist"
require_relative "../novelinfo"

module Narou
  #
  # 小説家になろうデベロッパーAPI操作クラス
  #
  class API
    # 一度に問い合わせする件数
    BATCH_LIMIT = 300

    # なろうAPIの結果の圧縮レベル(1〜5)
    GZIP_LEVEL = 5

    # リクエスト間ウェイト(sec)
    REQUEST_INTERVAL = 3

    #
    # なろうデベロッパーAPIから情報を取得
    #
    # api_url: なろうAPIのエンドポイントを指定。通常小説用と18禁小説用と分かれているため
    # ncodes: 取得したい小説のNコードを指定。文字列か配列を指定可能
    # of: 出力パラメータ（http://dev.syosetu.com/man/api/#of_parm 参照）
    #
    def initialize(api_url:, ncodes:, of:)
      @api_url = api_url
      @ncodes = Array(ncodes).map(&:downcase)
      @of = "n-#{of}"
      @splited_of = @of.split("-")
    end

    def [](key)
      @api_result[key]
    end

    def request
      @stores = []
      @ncodes.each_slice(BATCH_LIMIT).with_index do |ncodes, index|
        sleep REQUEST_INTERVAL unless index.zero?
        request_api(ncodes)
      end
      @stores
    end

    def request_api(ncodes, limit = BATCH_LIMIT)
      url = "#{@api_url}?gzip=#{GZIP_LEVEL}&ncode=#{ncodes.join("-")}&of=#{@of}&lim=#{limit}&out=json"
      URI.open(url) do |fp|
        data = Zlib::GzipReader.wrap(fp).read.force_encoding(Encoding::UTF_8)
        results = JSON.parse(data)
        return if results[0]["allcount"].zero?
        store_results(results.drop(1))
      end
    end

    def store_results(results)
      @stores += results.map do |result|
        result["ncode"].downcase!
        result["novel_type"] = result["noveltype"] if has_of?("nt")
        result["writer"] = result["writer"].to_s if has_of?("w")
        %w(general_firstup general_lastup novelupdated_at).each do |key|
          result[key] &&= Time.parse(result[key])
        end
        stat_end = result["end"]
        if stat_end
          result["end"] = stat_end.zero?
        end
        result
      end
    end

    def has_of?(type)
      @splited_of.include?(type)
    end

    def private_novels
      (@ncodes - @stores.map { |st| st["ncode"] }).map do |ncode|
        Downloader.get_data_by_target(ncode)["id"]
      end
    end
  end
end
