# frozen_string_literal: true

require 'will_paginate/array'

class CropsController < ApplicationController
  before_action :authenticate_member!, except: %i(index hierarchy search show)
  load_and_authorize_resource id_param: :slug
  skip_authorize_resource only: %i(hierarchy search)
  respond_to :html, :json, :rss, :csv, :svg
  responders :flash

  def index
    @crops = Crop.search('*', boost_by: %i(plantings_count harvests_count),
                              limit:    100,
                              page:     params[:page],
                              load:     false)
    @num_requested_crops = requested_crops.size if current_member
    @filename = filename
    respond_with @crops
  end

  def requested
    @requested = requested_crops.paginate(page: params[:page])
    respond_with @requested
  end

  def wrangle
    @approval_status = params[:approval_status]
    @crops = case @approval_status
             when "pending"
               Crop.pending_approval
             when "rejected"
               Crop.rejected
             else
               Crop.recent
             end.paginate(page: params[:page])

    @crop_wranglers = Role.crop_wranglers
    respond_with @crops
  end

  def gbif
    @crop = Crop.find(params[:crop_slug])
    @crop.update_gbif_data!
    respond_with @crop, location: @crop
  end

  def hierarchy
    @crops = Crop.toplevel.order(:name)
    respond_with @crops
  end

  def search
    @term = params[:term]

    @crops = CropSearchService.search(@term,
                                      page:           params[:page],
                                      per_page:       Crop.per_page,
                                      current_member:)

    respond_to do |format|
      format.html do
        render
      end
      format.json do
        render json: @crops.to_a
      end
    end
  end

  def show
    respond_to do |format|
      format.html do
        @posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
        @companions = @crop.companions.approved
      end
      format.svg do
        icon_data = @crop.svg_icon.presence || File.read(Rails.root.join("app/assets/images/icons/sprout.svg"))
        send_data(icon_data, type: "image/svg+xml", disposition: "inline")
      end
      format.json do
        render json: @crop.to_json(crop_json_fields)
      end
    end
  end

  def new
    @crop = Crop.new
    @crop.alternate_names.build
    @crop.scientific_names.build

    respond_with @crop
  end

  def edit
    @crop.alternate_names.build if @crop.alternate_names.blank?
    @crop.scientific_names.build if @crop.scientific_names.blank?
  end

  def create
    @crop = Crop.new(crop_params)

    if current_member.role? :crop_wrangler
      @crop.creator = current_member
    else
      @crop.requester = current_member
      @crop.approval_status = "pending"
    end

    if Crop.transaction { @crop.save && save_crop_names }
      notify_wranglers
    else
      @crop.alternate_names.build
      @crop.scientific_names.build
    end

    respond_with @crop
  end

  def update
    if can?(:wrangle, @crop)
      @crop.approval_status = 'rejected' if params.fetch("reject", false)
      @crop.approval_status = 'approved' if params.fetch("approve", false)
    end

    @crop.creator = current_member if @crop.approval_status == "pending"

    if @crop.update(crop_params)
      recreate_names('alt_name', 'alternate')
      recreate_names('sci_name', 'scientific')

      if @crop.approval_status_changed?(from: "pending", to: "approved")
        notifier.deliver_now!
        @crop.update_gbif_data!
      end
    else
      @crop.approval_status = @crop.approval_status_was
    end

    respond_with @crop
  end

  def destroy
    @crop = Crop.find_by!(slug: params[:slug])
    authorize! :destroy, @crop
    @crop.destroy
    respond_with @crop
  end

  private

  def notifier
    case @crop.approval_status
    when "approved"
      NotifierMailer.crop_request_approved(@crop.requester, @crop)
    when "rejected"
      NotifierMailer.crop_request_rejected(@crop.requester, @crop)
    end
  end

  def save_crop_names
    AlternateName.create!(names_params(:alt_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id, language: "EN" } })
    ScientificName.create!(names_params(:sci_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id } })
  end

  def notify_wranglers
    return if current_member.role? :crop_wrangler

    Role.crop_wranglers&.each do |w|
      NotifierMailer.new_crop_request(w, @crop).deliver_now!
    end
  end

  def recreate_names(param_name, name_type)
    return if params[param_name].blank?

    @crop.send("#{name_type}_names").each(&:destroy)
    params[param_name].each_value do |value|
      next if value.empty?

      if name_type == 'alternate'
        @crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id, language: "EN")
      else
        @crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id)
      end
    end
  end

  def crop_params
    params.require(:crop).permit(
      :name, :en_wikipedia_url,
      :parent_id, :perennial,
      :request_notes, :reason_for_rejection,
      :rejection_notes,
      :row_spacing, :spread, :height,
      :sowing_method, :sun_requirements, :growing_degree_days,
      scientific_names_attributes: %i(scientific_name _destroy id)
    )
  end

  def names_params(name_type)
    params.require(name_type).values&.reject { |n| n.empty? }
  end

  def filename
    "Growstuff-Crops-#{Time.zone.now.to_fs(:number)}.csv"
  end

  def crop_json_fields
    {
      include: {
        plantings: {
          include: {
            owner: { only: %i(id login_name location latitude longitude) }
          }
        },
        scientific_names: { only: [:name] }, alternate_names:  { only: %i(name language) }
      }
    }
  end

  def requested_crops
    current_member.requested_crops.pending_approval
  end
end
