class GekanatorQuestionsController < ApplicationController
  def index
    questions =
        GekanatorQuestion
        .accepted
        .includes(:gekanator_question_examples)
        .order(priority_weight: :desc, id: :asc)
        .to_a
    deprecated_tag_keys = deprecated_tag_keys_for(questions)

    render json: {
      questions: questions.filter_map { |question|
        json = question_json(question)
        next if hidden_question?(json[:condition], deprecated_tag_keys)

        json
      }
    }
  end

  private

  def question_json question
    condition = condition_json(question.condition).deep_symbolize_keys
    json = {
      record_id: question.id,
      id: question_id_for(question, condition),
      text: question_text_for(question, condition),
      kind: question.kind,
      condition: condition,
      source: question.source,
      priority_weight: question.priority_weight
    }
    if question.kind == 'post_similarity' || question.kind == 'tag'
      json[:example_answers] = example_answers_json(question)
    end
    json
  end

  def question_id_for question, condition
    case condition[:type]
    when 'tag'
      "tag:#{ condition[:key] }"
    when 'source'
      "source:#{ condition[:host] }"
    when 'original-year'
      "original-year:#{ condition[:year] }"
    when 'original-month'
      "original-month:#{ condition[:month] }"
    when 'original-month-day'
      "original-month-day:#{ condition[:monthDay] || condition[:month_day] }"
    when 'title-length-at-least'
      "title:length-at-least:#{ condition[:length] }"
    when 'title-length-greater-than'
      "title:length-at-least:#{ condition[:length].to_i + 1 }"
    when 'title-has-ascii'
      'title:ascii'
    when 'title-contains'
      "title:contains:#{ condition[:text] }"
    when 'post-similarity'
      "post-similarity:#{ question.id }"
    else
      "catalog:#{ question.id }"
    end
  end

  def condition_json condition
    json = condition.deep_dup.as_json

    if json['type'] == 'original-month-day' && json['monthDay'].blank?
      json['monthDay'] = json.delete('month_day')
    end

    if json['type'] == 'title-length-greater-than'
      json['type'] = 'title-length-at-least'
      json['length'] = json['length'].to_i + 1
    end

    json
  end

  def question_text_for question, condition
    return question.text unless question.kind == 'title'

    case condition[:type]
    when 'title-length-at-least'
      "タイトルは #{ condition[:length] } 文字以上?"
    when 'title-contains'
      "題名に「#{ condition[:text] }」が含まれる?"
    else
      question.text
    end
  end

  def example_answers_json question
    question
        .gekanator_question_examples
        .group_by(&:post_id)
        .transform_values { |examples| aggregate_answer(examples) }
  end

  def aggregate_answer examples
    examples
        .group_by(&:answer)
        .map { |answer, grouped| [answer, grouped.sum(&:weight), grouped.max_by(&:updated_at)&.updated_at] }
        .sort_by { |(_answer, weight, updated_at)| [-weight, -(updated_at&.to_f || 0)] }
        .first
        &.first
  end

  def deprecated_tag_keys_for questions
    tag_keys = questions.filter_map { |question|
      condition = condition_json(question.condition)
      next unless condition['type'] == 'tag'

      condition['key'].to_s.presence
    }.uniq
    return {} if tag_keys.empty?

    categories = []
    names = []
    tag_keys.each do |key|
      category, name = parse_tag_key(key)
      categories << category
      names << name
    end

    Tag
        .joins(:tag_name)
        .where(category: categories.uniq)
        .where(tag_names: { name: names.uniq })
        .where.not(deprecated_at: nil)
        .pluck('tags.category', 'tag_names.name')
        .each_with_object({ }) do |(category, name), h|
          h["#{ category }:#{ name }"] = true
        end
  end

  def hidden_question? condition, deprecated_tag_keys
    condition[:type] == 'tag' && deprecated_tag_keys[condition[:key].to_s]
  end

  def parse_tag_key key
    parts = key.to_s.split(':')
    [parts.first.to_s, parts.drop(1).join(':')]
  end
end
