class TagsController < ApplicationController
  def index
    post_id = params[:post]

    tags =
        if post_id.present?
          Tag.joins(:posts).where(posts: { id: post_id })
        else
          Tag.all
        end

    render json: tags.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
  end

  def autocomplete
    q = params[:q].to_s.strip
    return render json: [] if q.blank?

    with_nico = bool?(:nico, default: true)
    present_only = bool?(:present, default: true)

    alias_rows =
        TagName
        .where('name LIKE ?', "#{ q }%")
        .where.not(canonical_id: nil)
        .pluck(:canonical_id, :name)

    matched_alias_by_tag_name_id = { }
    canonical_ids = []

    alias_rows.each do |canonical_id, alias_name|
      canonical_ids << canonical_id
      matched_alias_by_tag_name_id[canonical_id] ||= alias_name
    end

    base = Tag.joins(:tag_name).includes(:tag_name)
    base = base.where('tags.post_count > 0') if present_only

    canonical_hit =
        base
        .where(((with_nico ? '(tags.category = ? AND tag_names.name LIKE ?) OR ' : '') +
                'tag_names.name LIKE ?'),
               *(with_nico ? ['nico', "nico:#{ q }%"] : []), "#{ q }%")

    tags =
        if canonical_ids.present?
          canonical_hit.or(base.where(tag_name_id: canonical_ids.uniq))
        else
          canonical_hit
        end

    tags = tags.order(Arel.sql('post_count DESC, tag_names.name')).limit(20).to_a

    render json: tags.map { |tag|
      tag.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
          .merge(matched_alias: matched_alias_by_tag_name_id[tag.tag_name_id])
    }
  end

  def show
    tag = Tag.find_by(id: params[:id])
    if tag
      render json: tag.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
    else
      head :not_found
    end
  end

  def show_by_name
    name = params[:name].to_s.strip
    return head :bad_request if name.blank?

    tag = Tag.joins(:tag_name).includes(:tag_name).find_by(tag_names: { name: })
    if tag
      render json: tag.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
    else
      head :not_found
    end
  end

  def update
    return head :unauthorized unless current_user
    return head :forbidden unless current_user.member?

    name = params[:name].presence
    category = params[:category].presence

    tag = Tag.find(params[:id])

    if name.present?
      tag.tag_name.update!(name:)
    end

    if category.present?
      tag.update!(category:)
    end

    render json: tag.as_json(methods: [:name])
  end
end
