class SamplesController < ApplicationController
  include InputSanitizeHelper
  include ActionView::Helpers::TextHelper
  include ApplicationHelper

  before_action :load_vars, only: [:edit, :update, :destroy, :show]
  before_action :load_vars_nested, only: [:new, :create]

  before_action :check_create_permissions, only: %i(new create)
  before_action :check_manage_permissions, only: %i(edit update destroy)

  def new
    respond_to do |format|
      format.html
      groups = @team.sample_groups.map do |g|
        { id: g.id, name: sanitize_input(g.name), color: g.color }
      end
      types = @team.sample_types.map do |t|
        { id: t.id, name: sanitize_input(t.name) }
      end
      format.json do
        render json: {
          sample_groups: groups.as_json,
          sample_types: types.as_json
        }
      end
    end
  end

  def create
    sample = Sample.new(
      user: current_user,
      team: @team
    )
    sample.last_modified_by = current_user
    errors = {
      init_fields: [],
      custom_fields: []
    };

    respond_to do |format|
      if params[:sample]
        # Sample name
        if params[:sample][:name]
          sample.name = params[:sample][:name]
        end

        # Sample type
        if params[:sample][:sample_type_id] != "-1"
          sample_type = SampleType.find_by_id(params[:sample][:sample_type_id])

          if sample_type
            sample.sample_type_id = params[:sample][:sample_type_id]
          end
        end

        # Sample group
        if params[:sample][:sample_group_id] != "-1"
          sample_group = SampleGroup.find_by_id(params[:sample][:sample_group_id])

          if sample_group
            sample.sample_group_id = params[:sample][:sample_group_id]
          end
        end
      end

      if !sample.save
        errors[:init_fields] = sample.errors.messages
      else
        # Sample was saved, we can add all newly added sample fields
        custom_fields_params.to_a.each do |id, val|
          scf = SampleCustomField.new(
            custom_field_id: id,
            sample_id: sample.id,
            value: val
          )

          if !scf.save
            errors[:custom_fields] << {
              "#{id}": scf.errors.messages
            }
          else
            sample_annotation_notification(sample, scf)
          end
        end
      end

      errors.delete_if { |k, v| v.blank? }
      if errors.empty?
        format.json do
          render json: {
            id: sample.id,
            flash: t(
              'samples.create.success_flash',
              sample: escape_input(sample.name),
              team: escape_input(@team.name)
            )
          },
          status: :ok
        end
      else
        format.json { render json: errors, status: :bad_request }
      end
    end
  end

  def show
    respond_to do |format|
      format.json do
        render json: {
          html: render_to_string(
            partial: 'info_sample_modal.html.erb'
          )
        }
      end
    end
  end

  def edit
    json = {
      sample: {
        name: escape_input(@sample.name),
        sample_type: @sample.sample_type.nil? ? "" : @sample.sample_type.id,
        sample_group: @sample.sample_group.nil? ? "" : @sample.sample_group.id,
        custom_fields: {}
      },
      sample_groups: @team.sample_groups.map do |g|
        { id: g.id, name: sanitize_input(g.name), color: g.color }
      end,
      sample_types: @team.sample_types.map do |t|
        { id: t.id, name: sanitize_input(t.name) }
      end
    }

    # Add custom fields ids as key (easier lookup on js side)
    @sample.sample_custom_fields.each do |scf|
      json[:sample][:custom_fields][scf.custom_field_id] = {
        sample_custom_field_id: scf.id,
        value: escape_input(scf.value)
      }
    end

    respond_to do |format|
      format.html
      format.json {
        render json: json
      }
    end
  end

  def update
    sample = Sample.find_by_id(params[:sample_id])
    sample.last_modified_by = current_user
    errors = {
      init_fields: [],
      sample_custom_fields: [],
      custom_fields: []
    };

    respond_to do |format|
      if sample
        if params[:sample]
          if params[:sample][:name]
            sample.name = params[:sample][:name]
          end

          # Check if user selected empty sample type
          if params[:sample][:sample_type_id] == "-1"
            sample.sample_type_id = nil
          elsif params[:sample][:sample_type_id]
            sample_type = SampleType.find_by_id(params[:sample][:sample_type_id])

            if sample_type
              sample.sample_type_id = params[:sample][:sample_type_id]
            end
          end

          # Check if user selected empty sample type
          if params[:sample][:sample_group_id] == "-1"
            sample.sample_group_id = nil
          elsif params[:sample][:sample_group_id]
            sample_group = SampleGroup.find_by_id(params[:sample][:sample_group_id])

            if sample_group
              sample.sample_group_id = params[:sample][:sample_group_id]
            end
          end
        end

        # Add all newly added sample fields
        custom_fields_params.to_a.each do |id, val|
          # Check if client is lying (SCF shouldn't exist)
          scf = SampleCustomField.where("custom_field_id = ? AND sample_id = ?", id, sample.id).take

          if scf
            old_text = scf.value
            # Well, client was naughty, no XMAS for him this year, update
            # existing SCF instead of creating new one
            scf.value = val

            if !scf.save
              # This client needs some lessons
              errors[:custom_fields] << {
                "#{id}": scf.errors.messages
              }
            else
              sample_annotation_notification(sample, scf, old_text)
            end
          else
            # SCF doesn't exist, create it
            scf = SampleCustomField.new(
              custom_field_id: id,
              sample_id: sample.id,
              value: val
            )

            if !scf.save
              errors[:custom_fields] << {
                "#{id}": scf.errors.messages
              }
            else
              sample_annotation_notification(sample, scf)
            end
          end
        end

        scf_to_delete = []
        # Update all existing custom values
        sample_custom_fields_params.to_a.each do |id, val|
          scf = SampleCustomField.find_by_id(id)

          if scf
            # SCF exists, but value is empty, add scf to queue to be deleted
            # (if everything is correct)
            if val.empty?
              scf_to_delete << scf
            else
              old_text = scf.value
              # SCF exists, update away
              scf.value = val

              if !scf.save
                errors[:sample_custom_fields] << {
                  "#{id}": scf.errors.messages
                }
              else
                sample_annotation_notification(sample, scf, old_text)
              end
            end
          else
            # SCF doesn't exist, we can't do much but yield error
            errors[:sample_custom_fields] << {
              "#{id}": I18n.t("samples.edit.scf_does_not_exist")
            }
          end
        end

        if !sample.save
          errors[:init_fields] = sample.errors.messages
        end

        errors.delete_if { |k, v| v.blank? }
        if errors.empty?
          # Now we can destroy empty scfs
          scf_to_delete.map(&:destroy)

          format.json do
            render json: {
              id: sample.id,
              flash: t(
                'samples.update.success_flash',
                sample: escape_input(sample.name),
                team: escape_input(@team.name)
              )
            },
            status: :ok
          end
        else
          format.json { render json: errors, status: :bad_request }
        end
      else
        format.json { render json: {}, status: :not_found }
      end
    end
  end

  def destroy
  end

  private

  def load_vars
    @sample = Sample.find_by_id(params[:id])
    @team = current_team

    unless @sample
      render_404
    end
  end

  def load_vars_nested
    @team = Team.find_by_id(params[:team_id])

    unless @team
      render_404
    end
  end

  def check_create_permissions
    render_403 unless can_create_samples?(@team)
  end

  def check_manage_permissions
    render_403 unless can_manage_sample?(@sample)
  end

  def sample_params
    params.require(:sample).permit(
      :name,
      :sample_type_id,
      :sample_group_id
    )
  end

  def custom_fields_params
    params.permit(custom_fields: {}).to_h[:custom_fields]
  end

  def sample_custom_fields_params
    params.permit(sample_custom_fields: {}).to_h[:sample_custom_fields]
  end

  def sample_annotation_notification(sample, scf, old_text = nil)
    table_url = params.fetch(:request_url) { :request_url_must_be_present }
    smart_annotation_notification(
      old_text: (old_text if old_text),
      new_text: scf.value,
      title: t('notifications.sample_annotation_title',
               user: current_user.full_name,
               column: scf.custom_field.name,
               sample: sample.name),
      message: t('notifications.sample_annotation_message_html',
                 sample: link_to(sample.name, table_url),
                 column: link_to(scf.custom_field.name, table_url))
    )
  end
end